include $(TOPDIR)/rules.mk
PKG_NAME:=haproxy
-PKG_VERSION:=1.8.20
+PKG_VERSION:=1.8.21
PKG_RELEASE:=1
PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://www.haproxy.org/download/1.8/src/
-PKG_HASH:=3228f78d5fe1dfbaccf41bf387e36b08eeef6e16330053cafde5fa303e262b16
+PKG_HASH:=34bc80bbaab6edae80add1e8b321636e50ccc56cb583040d98d5d245570680e1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
PKG_LICENSE:=GPL-2.0
#!/bin/bash
CLONEURL=http://git.haproxy.org/git/haproxy-1.8.git
-BASE_TAG=v1.8.20
+BASE_TAG=v1.8.21
TMP_REPODIR=tmprepo
PATCHESDIR=patches
+++ /dev/null
-commit cf2f1243373be97249567ffd259e975cc87068b8
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Mon Apr 29 13:12:02 2019 +0200
-
- BUG/MINOR: http: Call stream_inc_be_http_req_ctr() only one time per request
-
- The function stream_inc_be_http_req_ctr() is called at the beginning of the
- analysers AN_REQ_HTTP_PROCESS_FE/BE. It as an effect only on the backend. But we
- must be careful to call it only once. If the processing of HTTP rules is
- interrupted in the middle, when the analyser is resumed, we must not call it
- again. Otherwise, the tracked counters of the backend are incremented several
- times.
-
- This bug was reported in github. See issue #74.
-
- This fix should be backported as far as 1.6.
-
- (cherry picked from commit 1907ccc2f75b78ace1ee4acdfc60d48a76e3decd)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 319921866ea9ecc46215fea5679abc8efdfcbea5)
- [cf: HTX part was removed]
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/proto_http.c b/src/proto_http.c
-index ccacd6a4..556cabad 100644
---- a/src/proto_http.c
-+++ b/src/proto_http.c
-@@ -3420,8 +3420,10 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s
- req->buf->i,
- req->analysers);
-
-- /* just in case we have some per-backend tracking */
-- stream_inc_be_http_req_ctr(s);
-+ /* just in case we have some per-backend tracking. Only called the first
-+ * execution of the analyser. */
-+ if (!s->current_rule || s->current_rule_list != &px->http_req_rules)
-+ stream_inc_be_http_req_ctr(s);
-
- /* evaluate http-request rules */
- if (!LIST_ISEMPTY(&px->http_req_rules)) {
--- /dev/null
+commit db95dd53f88bb15e288b553de5c6687260756f03
+Author: Willy Tarreau <w@1wt.eu>
+Date: Tue Feb 12 10:59:32 2019 +0100
+
+ BUILD/MINOR: stream: avoid a build warning with threads disabled
+
+ gcc 6+ complains about a possible null-deref here due to the test in
+ objt_server() :
+
+ if (objt_server(s->target))
+ HA_ATOMIC_ADD(&objt_server(s->target)->counters.retries, 1);
+
+ Let's simply change it to __objt_server(). This can be backported to
+ 1.9 and 1.8.
+
+ (cherry picked from commit 1ef724e2169eaff7f0272278c3fba9b34d5c7f78)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 3d3b67f1877718abbbc8cc500aae373640e454e9)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/stream.c b/src/stream.c
+index f443cc74..99a133a9 100644
+--- a/src/stream.c
++++ b/src/stream.c
+@@ -746,7 +746,7 @@ static int sess_update_st_cer(struct stream *s)
+ si->state = SI_ST_REQ;
+ } else {
+ if (objt_server(s->target))
+- HA_ATOMIC_ADD(&objt_server(s->target)->counters.retries, 1);
++ HA_ATOMIC_ADD(&__objt_server(s->target)->counters.retries, 1);
+ HA_ATOMIC_ADD(&s->be->be_counters.retries, 1);
+ si->state = SI_ST_ASS;
+ }
+++ /dev/null
-commit c1620a52a3def02b4837376385c416c03ca874c4
-Author: Kevin Zhu <ipandtcp@gmail.com>
-Date: Fri Apr 26 14:00:01 2019 +0800
-
- BUG/MEDIUM: spoe: arg len encoded in previous frag frame but len changed
-
- Fragmented arg will do fetch at every encode time, each fetch may get
- different result if SMP_F_MAY_CHANGE, for example res.payload, but
- the length already encoded in first fragment of the frame, that will
- cause SPOA decode failed and waste resources.
-
- This patch must be backported to 1.9 and 1.8.
-
- (cherry picked from commit f7f54280c8106e92a55243f5d60f8587e79602d1)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 3a838e526cdbc00ded5362e66f1ef3a441abc3c1)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/proto/spoe.h b/include/proto/spoe.h
-index 002cf7d7..2cdca10b 100644
---- a/include/proto/spoe.h
-+++ b/include/proto/spoe.h
-@@ -121,7 +121,7 @@ spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len)
- * many bytes has been encoded. If <*off> is zero at the end, it means that all
- * data has been encoded. */
- static inline int
--spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end)
-+spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char **buf, char *end)
- {
- char *p = *buf;
- int ret;
-@@ -183,15 +183,16 @@ spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end)
- ret = spoe_encode_frag_buffer(chk->str, chk->len, &p, end);
- if (ret == -1)
- return -1;
-+ *len = chk->len;
- }
- else {
- /* The sample has been fragmented, encode remaining data */
-- ret = MIN(chk->len - *off, end - p);
-+ ret = MIN(*len - *off, end - p);
- memcpy(p, chk->str + *off, ret);
- p += ret;
- }
- /* Now update <*off> */
-- if (ret + *off != chk->len)
-+ if (ret + *off != *len)
- *off += ret;
- else
- *off = 0;
-diff --git a/include/types/spoe.h b/include/types/spoe.h
-index 53e7200c..cfaa42f8 100644
---- a/include/types/spoe.h
-+++ b/include/types/spoe.h
-@@ -304,6 +304,7 @@ struct spoe_context {
- struct spoe_message *curmsg; /* SPOE message from which to resume encoding */
- struct spoe_arg *curarg; /* SPOE arg in <curmsg> from which to resume encoding */
- unsigned int curoff; /* offset in <curarg> from which to resume encoding */
-+ unsigned int curlen; /* length of <curarg> need to be encode, for SMP_F_MAY_CHANGE data */
- unsigned int flags; /* SPOE_FRM_FL_* */
- } frag_ctx; /* Info about fragmented frames, valid on if SPOE_CTX_FL_FRAGMENTED is set */
- };
-diff --git a/src/flt_spoe.c b/src/flt_spoe.c
-index f6109778..0c0b3794 100644
---- a/src/flt_spoe.c
-+++ b/src/flt_spoe.c
-@@ -2172,6 +2172,7 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx,
- list_for_each_entry(arg, &msg->args, list) {
- ctx->frag_ctx.curarg = arg;
- ctx->frag_ctx.curoff = UINT_MAX;
-+ ctx->frag_ctx.curlen = 0;
-
- encode_argument:
- if (ctx->frag_ctx.curoff != UINT_MAX)
-@@ -2186,7 +2187,7 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx,
-
- /* Fetch the arguement value */
- smp = sample_process(s->be, s->sess, s, dir|SMP_OPT_FINAL, arg->expr, NULL);
-- ret = spoe_encode_data(smp, &ctx->frag_ctx.curoff, buf, end);
-+ ret = spoe_encode_data(&ctx->frag_ctx.curlen, smp, &ctx->frag_ctx.curoff, buf, end);
- if (ret == -1 || ctx->frag_ctx.curoff)
- goto too_big;
- }
--- /dev/null
+commit ccb3136727d1fd5efccd4689199aa29f530f6ed0
+Author: Dragan Dosen <ddosen@haproxy.com>
+Date: Tue Apr 30 00:38:36 2019 +0200
+
+ BUG/MINOR: haproxy: fix rule->file memory leak
+
+ When using the "use_backend" configuration directive, the configuration
+ file name stored as rule->file was not freed in some situations. This
+ was introduced in commit 4ed1c95 ("MINOR: http/conf: store the
+ use_backend configuration file and line for logs").
+
+ This patch should be backported to 1.9, 1.8 and 1.7.
+
+ (cherry picked from commit 2a7c20f602e5d40e9f23c703fbcb12e3af762337)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 60277d1a38b45b014478d33627a9bbb99cc9ee9e)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/haproxy.c b/src/haproxy.c
+index 6ea17a0c..61169243 100644
+--- a/src/haproxy.c
++++ b/src/haproxy.c
+@@ -2123,8 +2123,8 @@ void deinit(void)
+ if (rule->cond) {
+ prune_acl_cond(rule->cond);
+ free(rule->cond);
+- free(rule->file);
+ }
++ free(rule->file);
+ free(rule);
+ }
+
--- /dev/null
+commit a196f480348402a263aa65eed55261e9a59d2da7
+Author: Willy Tarreau <w@1wt.eu>
+Date: Thu Sep 6 14:52:21 2018 +0200
+
+ MINOR: connection: add new function conn_is_back()
+
+ This function returns true if the connection is a backend connection
+ and false if it's a frontend connection.
+
+ (cherry picked from commit 57f8185625f967f868187d336f995fac28f83fc5)
+ [wt: backported since used by next commit]
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/include/proto/connection.h b/include/proto/connection.h
+index 352f2fcc..31e746a1 100644
+--- a/include/proto/connection.h
++++ b/include/proto/connection.h
+@@ -912,6 +912,15 @@ static inline const struct mux_ops *alpn_get_mux(const struct ist token, int htt
+ return fallback;
+ }
+
++/* returns 0 if the connection is valid and is a frontend connection, otherwise
++ * returns 1 indicating it's a backend connection. And uninitialized connection
++ * also returns 1 to better handle the usage in the middle of initialization.
++ */
++static inline int conn_is_back(const struct connection *conn)
++{
++ return !objt_listener(conn->target);
++}
++
+ /* finds the best mux for incoming connection <conn> and mode <http_mode> for
+ * the proxy. Null cannot be returned unless there's a serious bug somewhere
+ * else (no fallback mux registered).
+++ /dev/null
-commit 72fdff1fdb5b82685dc3d2db23ece042195a0cbd
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Fri Apr 26 14:30:15 2019 +0200
-
- MINOR: spoe: Use the sample context to pass frag_ctx info during encoding
-
- This simplifies the API and hide the details in the sample. This way, only
- string and binary are aware of these info, because other types cannot be
- partially encoded.
-
- This patch may be backported to 1.9 and 1.8.
-
- (cherry picked from commit 85db3212b87b33f1a39a688546f4f53a5c4ba4da)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit b93366e3ee44f5de93f01569fcdcd602f6d0703f)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/proto/spoe.h b/include/proto/spoe.h
-index 2cdca10b..cce13e50 100644
---- a/include/proto/spoe.h
-+++ b/include/proto/spoe.h
-@@ -117,11 +117,9 @@ spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len)
- *
- * If the value is too big to be encoded, depending on its type, then encoding
- * failed or the value is partially encoded. Only strings and binaries can be
-- * partially encoded. In this case, the offset <*off> is updated to known how
-- * many bytes has been encoded. If <*off> is zero at the end, it means that all
-- * data has been encoded. */
-+ * partially encoded. */
- static inline int
--spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char **buf, char *end)
-+spoe_encode_data(struct sample *smp, char **buf, char *end)
- {
- char *p = *buf;
- int ret;
-@@ -164,12 +162,16 @@ spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char
-
- case SMP_T_STR:
- case SMP_T_BIN: {
-+ /* If defined, get length and offset of the sample by reading the sample
-+ * context. ctx.a[0] is the pointer to the length and ctx.a[1] is the
-+ * pointer to the offset. If the offset is greater than 0, it means the
-+ * sample is partially encoded. In this case, we only need to encode the
-+ * reamining. When all the sample is encoded, the offset is reset to 0.
-+ * So the caller know it can try to encode the next sample. */
- struct chunk *chk = &smp->data.u.str;
-+ unsigned int *len = (smp->ctx.a[0] ? smp->ctx.a[0] : 0);
-+ unsigned int *off = (smp->ctx.a[1] ? smp->ctx.a[1] : 0);
-
-- /* Here, we need to know if the sample has already been
-- * partially encoded. If yes, we only need to encode the
-- * remaining, <*off> reprensenting the number of bytes
-- * already encoded. */
- if (!*off) {
- /* First evaluation of the sample : encode the
- * type (string or binary), the buffer length
-diff --git a/src/flt_spoe.c b/src/flt_spoe.c
-index 0c0b3794..66d8b045 100644
---- a/src/flt_spoe.c
-+++ b/src/flt_spoe.c
-@@ -2187,7 +2187,9 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx,
-
- /* Fetch the arguement value */
- smp = sample_process(s->be, s->sess, s, dir|SMP_OPT_FINAL, arg->expr, NULL);
-- ret = spoe_encode_data(&ctx->frag_ctx.curlen, smp, &ctx->frag_ctx.curoff, buf, end);
-+ smp->ctx.a[0] = &ctx->frag_ctx.curlen;
-+ smp->ctx.a[1] = &ctx->frag_ctx.curoff;
-+ ret = spoe_encode_data(smp, buf, end);
- if (ret == -1 || ctx->frag_ctx.curoff)
- goto too_big;
- }
--- /dev/null
+commit ad838cae47c15dc0be018be6c081e241d41ed45f
+Author: Olivier Houchard <ohouchard@haproxy.com>
+Date: Fri May 3 20:56:19 2019 +0200
+
+ BUG/MEDIUM: ssl: Use the early_data API the right way.
+
+ We can only read early data if we're a server, and write if we're a client,
+ so don't attempt to mix both.
+
+ This should be backported to 1.8 and 1.9.
+
+ (cherry picked from commit 010941f87605e8219d25becdbc652350a687d6a2)
+ [wt: minor context adjustments due to latest SSL API changes in 2.0]
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 3d14cbddd971f8f301f795c8446ae2bcadab6cc2)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/backend.c b/src/backend.c
+index 0cf14cfd..c43fb72f 100644
+--- a/src/backend.c
++++ b/src/backend.c
+@@ -1214,10 +1214,8 @@ int connect_server(struct stream *s)
+ (srv->ssl_ctx.options & SRV_SSL_O_EARLY_DATA) &&
+ (cli_conn->flags & CO_FL_EARLY_DATA) &&
+ !channel_is_empty(si_oc(&s->si[1])) &&
+- srv_conn->flags & CO_FL_SSL_WAIT_HS) {
++ srv_conn->flags & CO_FL_SSL_WAIT_HS)
+ srv_conn->flags &= ~(CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN);
+- srv_conn->flags |= CO_FL_EARLY_SSL_HS;
+- }
+ #endif
+
+ if (err != SF_ERR_NONE)
+diff --git a/src/ssl_sock.c b/src/ssl_sock.c
+index 1fc01c1c..76767242 100644
+--- a/src/ssl_sock.c
++++ b/src/ssl_sock.c
+@@ -5549,7 +5549,7 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
+ if (!conn->xprt_ctx)
+ goto out_error;
+
+- if (conn->flags & CO_FL_HANDSHAKE)
++ if (conn->flags & (CO_FL_HANDSHAKE | CO_FL_EARLY_SSL_HS))
+ /* a handshake was requested */
+ return 0;
+
+@@ -5578,7 +5578,7 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
+ }
+
+ #if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+- if (!SSL_is_init_finished(conn->xprt_ctx)) {
++ if (!SSL_is_init_finished(conn->xprt_ctx) && conn_is_back(conn)) {
+ unsigned int max_early;
+
+ if (objt_listener(conn->target))
+@@ -5593,8 +5593,7 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
+ if (try + conn->sent_early_data > max_early) {
+ try -= (try + conn->sent_early_data) - max_early;
+ if (try <= 0) {
+- if (!(conn->flags & CO_FL_EARLY_SSL_HS))
+- conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
++ conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
+ break;
+ }
+ }
+@@ -5602,10 +5601,8 @@ static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int fl
+ if (ret == 1) {
+ ret = written_data;
+ conn->sent_early_data += ret;
+- if (objt_server(conn->target)) {
+- conn->flags &= ~CO_FL_EARLY_SSL_HS;
++ if (objt_server(conn->target))
+ conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN | CO_FL_EARLY_DATA;
+- }
+
+ }
+
+++ /dev/null
-commit dfc3718f0a302ea3deb5f1a325d35fce0e4cfa48
-Author: Yann Cézard <ycezard@viareport.com>
-Date: Thu Apr 25 14:48:38 2019 +0200
-
- DOC: contrib/modsecurity: Typos and fix the reject example
-
- Thanks to https://www.mail-archive.com/haproxy@formilux.org/msg30056.html
-
- This patch may be backported to 1.9 and 1.8.
-
- (cherry picked from commit 494ddbff478d880e48de490f2689607addac70bc)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 850896603086877641272d6e4075e66bd91f2e50)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/contrib/modsecurity/README b/contrib/modsecurity/README
-index e6cb305e..8031389d 100644
---- a/contrib/modsecurity/README
-+++ b/contrib/modsecurity/README
-@@ -88,15 +88,15 @@ HAProxy configuration. For example:
- balance roundrobin
- timeout connect 5s
- timeout server 3m
-- server iprep1 127.0.0.1:12345
-+ server modsec1 127.0.0.1:12345
-
- The modsecurity action is returned in a variable called txn.modsec.code. It
- contains the HTTP returned code. If the variable contains 0, the request is
- clean.
-
-- tcp-request content reject if { var(txn.modsec.code) -m int gt 0 }
-+ http-request deny if { var(txn.modsec.code) -m int gt 0 }
-
--With this rule, all the request not clean are reected.
-+With this rule, all the request not clean are rejected.
-
-
- Known bugs, limitations and TODO list
--- /dev/null
+commit ae6824e2c836f1714827e9d3f585e729ea022f30
+Author: Willy Tarreau <w@1wt.eu>
+Date: Sun May 5 06:54:22 2019 +0200
+
+ BUG/MEDIUM: checks: make sure the warmup task takes the server lock
+
+ The server warmup task is used when a server uses the "slowstart"
+ parameter. This task affects the server's weight and maxconn, and may
+ dequeue pending connections from the queue. This must be done under
+ the server's lock, which was not the case.
+
+ This must be backported to 1.9 and 1.8.
+
+ (cherry picked from commit 4fc49a9aabacc8028877e2dcbdb54d8a19c398c4)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 207ba5a6bc1c03f2ba15ac3cd49bfa756fb760bb)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/checks.c b/src/checks.c
+index 1ecc4050..fbe14ca1 100644
+--- a/src/checks.c
++++ b/src/checks.c
+@@ -1445,12 +1445,16 @@ static struct task *server_warmup(struct task *t)
+ (s->next_state != SRV_ST_STARTING))
+ return t;
+
++ HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
++
+ /* recalculate the weights and update the state */
+ server_recalc_eweight(s);
+
+ /* probably that we can refill this server with a bit more connections */
+ pendconn_grab_from_px(s);
+
++ HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
++
+ /* get back there in 1 second or 1/20th of the slowstart interval,
+ * whichever is greater, resulting in small 5% steps.
+ */
+++ /dev/null
-commit 95cf225d099dcb49eefcf4f5b648be604414ae0c
-Author: Yann Cézard <ycezard@viareport.com>
-Date: Thu Apr 25 14:30:23 2019 +0200
-
- BUG/MEDIUM: contrib/modsecurity: If host header is NULL, don't try to strdup it
-
- I discovered this bug when running OWASP regression tests against HAProxy +
- modsecurity-spoa (it's a POC to evaluate how it is working). I found out that
- modsecurity spoa will crash when the request doesn't have any Host header.
-
- See the pull request #86 on github for details.
-
- This patch must be backported to 1.9 and 1.8.
-
- (cherry picked from commit bf60f6b8033deddc86de5357d6099c7593fe44cc)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit d988e3dddcbe1f48f3b24d1bb529fc9ecefde180)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/contrib/modsecurity/modsec_wrapper.c b/contrib/modsecurity/modsec_wrapper.c
-index 271ec15d..2f3987b4 100644
---- a/contrib/modsecurity/modsec_wrapper.c
-+++ b/contrib/modsecurity/modsec_wrapper.c
-@@ -325,7 +325,11 @@ int modsecurity_process(struct worker *worker, struct modsecurity_parameters *pa
- req->content_type = apr_table_get(req->headers_in, "Content-Type");
- req->content_encoding = apr_table_get(req->headers_in, "Content-Encoding");
- req->hostname = apr_table_get(req->headers_in, "Host");
-- req->parsed_uri.hostname = chunk_strdup(req, req->hostname, strlen(req->hostname));
-+ if (req->hostname != NULL) {
-+ req->parsed_uri.hostname = chunk_strdup(req, req->hostname, strlen(req->hostname));
-+ } else {
-+ req->parsed_uri.hostname = NULL;
-+ }
-
- lang = apr_table_get(req->headers_in, "Content-Languages");
- if (lang != NULL) {
--- /dev/null
+commit dc90debd638a2aa94e062e66c00b1b8a9ab3c115
+Author: Willy Tarreau <w@1wt.eu>
+Date: Sun May 5 10:11:39 2019 +0200
+
+ BUG/MINOR: logs/threads: properly split the log area upon startup
+
+ If logs were emitted before creating the threads, then the dataptr pointer
+ keeps a copy of the end of the log header. Then after the threads are
+ created, the headers are reallocated for each thread. However the end
+ pointer was not reset until the end of the first second, which may result
+ in logs emitted by multiple threads during the first second to be mangled,
+ or possibly in some cases to use a memory area that was reused for something
+ else. The fix simply consists in reinitializing the end pointers immediately
+ when the threads are created.
+
+ This fix must be backported to 1.9 and 1.8.
+
+ (cherry picked from commit 55e2f5ad14a6d9ec39c218296ad3f1a521cc74a1)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 55c3bd480fbbbb4692368655d3d4a425b5248e2a)
+ [wt: ctx, buf->chunk]
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/log.c b/src/log.c
+index 313fa55d..1d8cf335 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -212,11 +212,13 @@ char default_rfc5424_sd_log_format[] = "- ";
+ * update_log_hdr().
+ */
+ THREAD_LOCAL char *logheader = NULL;
++THREAD_LOCAL char *logheader_end = NULL;
+
+ /* This is a global syslog header for messages in RFC5424 format. It is
+ * updated by update_log_hdr_rfc5424().
+ */
+ THREAD_LOCAL char *logheader_rfc5424 = NULL;
++THREAD_LOCAL char *logheader_rfc5424_end = NULL;
+
+ /* This is a global syslog message buffer, common to all outgoing
+ * messages. It contains only the data part.
+@@ -986,11 +988,10 @@ char *lf_port(char *dst, struct sockaddr *sockaddr, size_t size, struct logforma
+ static char *update_log_hdr(const time_t time)
+ {
+ static THREAD_LOCAL long tvsec;
+- static THREAD_LOCAL char *dataptr = NULL; /* backup of last end of header, NULL first time */
+ static THREAD_LOCAL struct chunk host = { NULL, 0, 0 };
+ static THREAD_LOCAL int sep = 0;
+
+- if (unlikely(time != tvsec || dataptr == NULL)) {
++ if (unlikely(time != tvsec || logheader_end == NULL)) {
+ /* this string is rebuild only once a second */
+ struct tm tm;
+ int hdr_len;
+@@ -1016,12 +1017,12 @@ static char *update_log_hdr(const time_t time)
+ if (hdr_len < 0 || hdr_len > global.max_syslog_len)
+ hdr_len = global.max_syslog_len;
+
+- dataptr = logheader + hdr_len;
++ logheader_end = logheader + hdr_len;
+ }
+
+- dataptr[0] = 0; // ensure we get rid of any previous attempt
++ logheader_end[0] = 0; // ensure we get rid of any previous attempt
+
+- return dataptr;
++ return logheader_end;
+ }
+
+ /* Re-generate time-based part of the syslog header in RFC5424 format at
+@@ -1031,10 +1032,9 @@ static char *update_log_hdr(const time_t time)
+ static char *update_log_hdr_rfc5424(const time_t time)
+ {
+ static THREAD_LOCAL long tvsec;
+- static THREAD_LOCAL char *dataptr = NULL; /* backup of last end of header, NULL first time */
+ const char *gmt_offset;
+
+- if (unlikely(time != tvsec || dataptr == NULL)) {
++ if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
+ /* this string is rebuild only once a second */
+ struct tm tm;
+ int hdr_len;
+@@ -1056,12 +1056,12 @@ static char *update_log_hdr_rfc5424(const time_t time)
+ if (hdr_len < 0 || hdr_len > global.max_syslog_len)
+ hdr_len = global.max_syslog_len;
+
+- dataptr = logheader_rfc5424 + hdr_len;
++ logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
+ }
+
+- dataptr[0] = 0; // ensure we get rid of any previous attempt
++ logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
+
+- return dataptr;
++ return logheader_rfc5424_end;
+ }
+
+ /*
+@@ -1369,7 +1369,9 @@ static void deinit_log_buffers_per_thread()
+ int init_log_buffers()
+ {
+ logheader = my_realloc2(logheader, global.max_syslog_len + 1);
++ logheader_end = NULL;
+ logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
++ logheader_rfc5424_end = NULL;
+ logline = my_realloc2(logline, global.max_syslog_len + 1);
+ logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
+ if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
+++ /dev/null
-commit 86860896dc1841eb59cb95832d76a8093e8dc8c5
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 10:55:38 2019 +0200
-
- MINOR: examples: Use right locale for the last changelog date in haproxy.spec
-
- The last changelog entry was stamped with the wrong locale.
-
- No need to backport, it is specific to 1.8
-
-diff --git a/examples/haproxy.spec b/examples/haproxy.spec
-index f3e0c7e0..fe5215d7 100644
---- a/examples/haproxy.spec
-+++ b/examples/haproxy.spec
-@@ -74,7 +74,7 @@ fi
- %attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name}
-
- %changelog
--* jeu. avril 25 2019 Christopher Faulet <cfaulet@haproxy.com>
-+* Thu Apr 25 2019 Christopher Faulet <cfaulet@haproxy.com>
- - updated to 1.8.20
-
- * Mon Feb 11 2019 Willy Tarreau <w@1wt.eu>
+++ /dev/null
-commit 83af1f6b65806982640679823228976deebf5202
-Author: Willy Tarreau <w@1wt.eu>
-Date: Tue Apr 30 11:43:43 2019 +0200
-
- BUG/MAJOR: map/acl: real fix segfault during show map/acl on CLI
-
- A previous commit 8d85aa44d ("BUG/MAJOR: map: fix segfault during
- 'show map/acl' on cli.") was provided to address a concurrency issue
- between "show acl" and "clear acl" on the CLI. Sadly the code placed
- there was copy-pasted without changing the element type (which was
- struct stream in the original code) and not tested since the crash
- is still present.
-
- The reproducer is simple : load a large ACL file (e.g. geolocation
- addresses), issue "show acl #0" in loops in one window and issue a
- "clear acl #0" in the other one, haproxy crashes.
-
- This fix was also tested with threads enabled and looks good since
- the locking seems to work correctly in these areas though. It will
- have to be backported as far as 1.6 since the commit above went
- that far as well...
-
- (cherry picked from commit 49ee3b2f9a9e5d0b8d394938df527aa645ce72b4)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit ac4be10f62ef72962d9cf0e6f2619e1e1c370d62)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/pattern.c b/src/pattern.c
-index 7eea9d96..21639569 100644
---- a/src/pattern.c
-+++ b/src/pattern.c
-@@ -1651,7 +1651,7 @@ int pat_ref_delete_by_id(struct pat_ref *ref, struct pat_ref_elt *refelt)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- list_for_each_entry(expr, &ref->pat, list)
-@@ -1691,7 +1691,7 @@ int pat_ref_delete(struct pat_ref *ref, const char *key)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- list_for_each_entry(expr, &ref->pat, list)
-@@ -2086,7 +2086,7 @@ void pat_ref_reload(struct pat_ref *ref, struct pat_ref *replace)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- LIST_DEL(&elt->list);
-@@ -2175,7 +2175,7 @@ void pat_ref_prune(struct pat_ref *ref)
- LIST_DEL(&bref->users);
- LIST_INIT(&bref->users);
- if (elt->list.n != &ref->head)
-- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users);
-+ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users);
- bref->ref = elt->list.n;
- }
- LIST_DEL(&elt->list);
--- /dev/null
+commit b6aa92725eaf823c4b18316729eae494783daa85
+Author: Olivier Houchard <ohouchard@haproxy.com>
+Date: Mon May 6 18:58:48 2019 +0200
+
+ MINOR: doc: Document allow-0rtt on the server line.
+
+ Briefly document allow-0rtt on the server line, and only the part that apply
+ to 1.8 and 1.9.
+
+ This should be backported to 1.8 and 1.9.
+
+ (cherry picked from commit 8cb2d2e94199b8a6a9186ec12ee8146421a5d227)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 895b6a4568287b87d69599f347da01dcd1cfc9b2)
+ [wt: context]
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/doc/configuration.txt b/doc/configuration.txt
+index 7768e761..720b32e3 100644
+--- a/doc/configuration.txt
++++ b/doc/configuration.txt
+@@ -11223,6 +11223,10 @@ agent-port <port>
+
+ See also the "agent-check" and "agent-inter" parameters.
+
++allow-0rtt
++ Allow sending early data to the server when using TLS 1.3.
++ Note that early data will be sent only if the client used early data.
++
+ backup
+ When "backup" is present on a server line, the server is only used in load
+ balancing when all other non-backup servers are unavailable. Requests coming
+++ /dev/null
-commit 7bd7a8d2b8889f604b807c21190d2e70328d6674
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 12:17:13 2019 +0200
-
- BUG/MEDIUM: listener: Fix how unlimited number of consecutive accepts is handled
-
- There is a bug when global.tune.maxaccept is set to -1 (no limit). It is pretty
- visible with one process (nbproc sets to 1). The functions listener_accept() and
- accept_queue_process() don't expect to handle negative maxaccept values. So
- instead of accepting incoming connections without any limit, none are never
- accepted and HAProxy loop infinitly in the scheduler.
-
- When there are 2 or more processes, the bug is a bit more subtile. The limit for
- a listener is set to 1. So only one connection is accepted at a time by a given
- listener. This happens because the listener's maxaccept value is an unsigned
- integer. In check_config_validity(), it is first set to UINT_MAX (-1 casted in
- an unsigned integer), and then some calculations on it leads to an integer
- overflow.
-
- To fix the bug, the listener's maxaccept value is now a signed integer. So, if a
- negative value is set for global.tune.maxaccept, we keep it untouched for the
- listener and no calculation is made on it. Then, in the listener code, this
- signed value is casted to a unsigned one. It simplifies all tests instead of
- dealing with negative values. So, it limits the number of connections accepted
- at a time to UINT_MAX at most. But, honestly, it not an issue.
-
- This patch must be backported to 1.9 and 1.8.
-
- (cherry picked from commit 102854cbbaa4d22466dddec9035d411db244082f)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit bca4fb2d9d7f2966d9f8270fa1796fdc0dfc866d)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/types/listener.h b/include/types/listener.h
-index ea2eadb5..16ef6d7a 100644
---- a/include/types/listener.h
-+++ b/include/types/listener.h
-@@ -196,7 +196,7 @@ struct listener {
- int nbconn; /* current number of connections on this listener */
- int maxconn; /* maximum connections allowed on this listener */
- unsigned int backlog; /* if set, listen backlog */
-- unsigned int maxaccept; /* if set, max number of connections accepted at once */
-+ int maxaccept; /* if set, max number of connections accepted at once (-1 when disabled) */
- struct list proto_list; /* list in the protocol header */
- int (*accept)(struct listener *l, int fd, struct sockaddr_storage *addr); /* upper layer's accept() */
- enum obj_type *default_target; /* default target to use for accepted sessions or NULL */
-diff --git a/src/listener.c b/src/listener.c
-index 821c931a..74990c45 100644
---- a/src/listener.c
-+++ b/src/listener.c
-@@ -406,7 +406,7 @@ void listener_accept(int fd)
- {
- struct listener *l = fdtab[fd].owner;
- struct proxy *p;
-- int max_accept;
-+ unsigned int max_accept;
- int next_conn = 0;
- int next_feconn = 0;
- int next_actconn = 0;
-@@ -420,6 +420,10 @@ void listener_accept(int fd)
- if (!l)
- return;
- p = l->bind_conf->frontend;
-+
-+ /* if l->maxaccept is -1, then max_accept is UINT_MAX. It is not really
-+ * illimited, but it is probably enough.
-+ */
- max_accept = l->maxaccept ? l->maxaccept : 1;
-
- if (!(l->options & LI_O_UNLIMITED) && global.sps_lim) {
-@@ -480,7 +484,7 @@ void listener_accept(int fd)
- * worst case. If we fail due to system limits or temporary resource
- * shortage, we try again 100ms later in the worst case.
- */
-- for (; max_accept-- > 0; next_conn = next_feconn = next_actconn = 0) {
-+ for (; max_accept; next_conn = next_feconn = next_actconn = 0, max_accept--) {
- struct sockaddr_storage addr;
- socklen_t laddr = sizeof(addr);
- unsigned int count;
--- /dev/null
+commit dcb8c973fdfa6b96b651b06740b74b1d492cb92d
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Mon May 6 09:53:10 2019 +0200
+
+ BUG/MEDIUM: spoe: Be sure the sample is found before setting its context
+
+ When a sample fetch is encoded, we use its context to set info about the
+ fragmentation. But if the sample is not found, the function sample_process()
+ returns NULL. So we me be sure the sample exists before setting its context.
+
+ This patch must be backported to 1.9 and 1.8.
+
+ (cherry picked from commit 3b1d004d410129efcf365643d2583dcd2cb6ed0f)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 2e062883b8f94500314b7c863c1a13e3c9af23ca)
+ [wt: adjust buf->chunk context]
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/include/proto/spoe.h b/include/proto/spoe.h
+index cce13e50..74fe9466 100644
+--- a/include/proto/spoe.h
++++ b/include/proto/spoe.h
+@@ -169,8 +169,8 @@ spoe_encode_data(struct sample *smp, char **buf, char *end)
+ * reamining. When all the sample is encoded, the offset is reset to 0.
+ * So the caller know it can try to encode the next sample. */
+ struct chunk *chk = &smp->data.u.str;
+- unsigned int *len = (smp->ctx.a[0] ? smp->ctx.a[0] : 0);
+- unsigned int *off = (smp->ctx.a[1] ? smp->ctx.a[1] : 0);
++ unsigned int *len = smp->ctx.a[0];
++ unsigned int *off = smp->ctx.a[1];
+
+ if (!*off) {
+ /* First evaluation of the sample : encode the
+diff --git a/src/flt_spoe.c b/src/flt_spoe.c
+index aeb1fde7..9f745943 100644
+--- a/src/flt_spoe.c
++++ b/src/flt_spoe.c
+@@ -2187,8 +2187,10 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx,
+
+ /* Fetch the arguement value */
+ smp = sample_process(s->be, s->sess, s, dir|SMP_OPT_FINAL, arg->expr, NULL);
+- smp->ctx.a[0] = &ctx->frag_ctx.curlen;
+- smp->ctx.a[1] = &ctx->frag_ctx.curoff;
++ if (smp) {
++ smp->ctx.a[0] = &ctx->frag_ctx.curlen;
++ smp->ctx.a[1] = &ctx->frag_ctx.curoff;
++ }
+ ret = spoe_encode_data(smp, buf, end);
+ if (ret == -1 || ctx->frag_ctx.curoff)
+ goto too_big;
--- /dev/null
+commit 42c7b87b18bce3a12a8b1a08435e393ed543f79f
+Author: n9@users.noreply.github.com <n9@users.noreply.github.com>
+Date: Fri Aug 23 11:21:05 2019 +0200
+
+ DOC: fixed typo in management.txt
+
+ replaced fot -> for
+ added two periods
+
+ (cherry picked from commit 25a1c8e4539c12c19a3fe04aabe563cdac5e36db)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 7c80af0fb53f2a1d93a597f7d97cc67996e36be2)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit 4c43256c7e78643f8972f4248ed11688137609bb)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/doc/management.txt b/doc/management.txt
+index 8fdea722..e79b3cd0 100644
+--- a/doc/management.txt
++++ b/doc/management.txt
+@@ -1483,8 +1483,8 @@ enable agent <backend>/<server>
+ level "admin".
+
+ enable dynamic-cookie backend <backend>
+- Enable the generation of dynamic cookies fot the backend <backend>
+- A secret key must also be provided
++ Enable the generation of dynamic cookies for the backend <backend>.
++ A secret key must also be provided.
+
+ enable frontend <frontend>
+ Resume a frontend which was temporarily stopped. It is possible that some of
+++ /dev/null
-commit 6e580b6e744011e87c337ebe2c082acfd5ca835a
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 14:03:56 2019 +0200
-
- MINOR: config: Test validity of tune.maxaccept during the config parsing
-
- Only -1 and positive integers from 0 to INT_MAX are accepted. An error is
- triggered during the config parsing for any other values.
-
- This patch may be backported to all supported versions.
-
- (cherry picked from commit 6b02ab87348090efec73b1dd24f414239669f279)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 2bbc40f8bc9a52ba0d03b25270ac0129cca29bba)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/cfgparse.c b/src/cfgparse.c
-index c178538b..8e325416 100644
---- a/src/cfgparse.c
-+++ b/src/cfgparse.c
-@@ -789,6 +789,8 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
- global.tune.maxpollevents = atol(args[1]);
- }
- else if (!strcmp(args[0], "tune.maxaccept")) {
-+ long max;
-+
- if (alertif_too_many_args(1, file, linenum, args, &err_code))
- goto out;
- if (global.tune.maxaccept != 0) {
-@@ -801,7 +803,13 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
- err_code |= ERR_ALERT | ERR_FATAL;
- goto out;
- }
-- global.tune.maxaccept = atol(args[1]);
-+ max = atol(args[1]);
-+ if (/*max < -1 || */max > INT_MAX) {
-+ ha_alert("parsing [%s:%d] : '%s' expects -1 or an integer from 0 to INT_MAX.\n", file, linenum, args[0]);
-+ err_code |= ERR_ALERT | ERR_FATAL;
-+ goto out;
-+ }
-+ global.tune.maxaccept = max;
- }
- else if (!strcmp(args[0], "tune.chksize")) {
- if (alertif_too_many_args(1, file, linenum, args, &err_code))
--- /dev/null
+commit 7ae43ca14823ae61c547ac08c0a237b6ec55e04a
+Author: Willy Tarreau <w@1wt.eu>
+Date: Mon Aug 26 10:37:39 2019 +0200
+
+ BUG/MINOR: mworker: disable SIGPROF on re-exec
+
+ If haproxy is built with profiling enabled with -pg, it is possible to
+ see the master quit during a reload while it's re-executing itself with
+ error code 155 (signal 27) saying "Profile timer expired)". This happens
+ if the SIGPROF signal is delivered during the execve() call while the
+ handler was already unregistered. The issue itself is not directly inside
+ haproxy but it's easy to address. This patch disables this signal before
+ calling execvp() during a master reload. A simple test for this consists
+ in running this little script with haproxy started in master-worker mode :
+
+ $ while usleep 50000; do killall -USR2 haproxy; done
+
+ This fix should be backported to all versions using the master-worker
+ model.
+
+ (cherry picked from commit e0d86e2c1caaaa2141118e3309d479de5f67e855)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit f259fcc00a04e633a7a64f894a719f78f3644867)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit f2c9971cb51d28f0c4422d1197447406aa72e945)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/haproxy.c b/src/haproxy.c
+index 61169243..ef5a05cc 100644
+--- a/src/haproxy.c
++++ b/src/haproxy.c
+@@ -705,6 +705,7 @@ static void mworker_reload()
+ }
+
+ ha_warning("Reexecuting Master process\n");
++ signal(SIGPROF, SIG_IGN);
+ execvp(next_argv[0], next_argv);
+
+ ha_warning("Failed to reexecute the master process [%d]: %s\n", pid, strerror(errno));
+++ /dev/null
-commit c6e03c1495fa51f9a98ed0bbe3230313c7c7201c
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Tue Apr 30 14:08:41 2019 +0200
-
- CLEANUP: config: Don't alter listener->maxaccept when nbproc is set to 1
-
- This patch only removes a useless calculation on listener->maxaccept when nbproc
- is set to 1. Indeed, the following formula has no effet in such case:
-
- listener->maxaccept = (listener->maxaccept + nbproc - 1) / nbproc;
-
- This patch may be backported as far as 1.5.
-
- (cherry picked from commit 02f3cf19ed803d20aff9294ce7cb732489951ff5)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 14203e3cf9404e57de5e274b453f0fe4f2174924)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/cfgparse.c b/src/cfgparse.c
-index 8e325416..3f6ea352 100644
---- a/src/cfgparse.c
-+++ b/src/cfgparse.c
-@@ -9018,9 +9018,8 @@ out_uri_auth_compat:
- * is bound to. Rememeber that maxaccept = -1 must be kept as it is
- * used to disable the limit.
- */
-- if (listener->maxaccept > 0) {
-- if (nbproc > 1)
-- listener->maxaccept = (listener->maxaccept + 1) / 2;
-+ if (listener->maxaccept > 0 && nbproc > 1) {
-+ listener->maxaccept = (listener->maxaccept + 1) / 2;
- listener->maxaccept = (listener->maxaccept + nbproc - 1) / nbproc;
- }
-
--- /dev/null
+commit ae9e97ed9d2ac46515e0fba1cb71028169cc3be6
+Author: Willy Tarreau <w@1wt.eu>
+Date: Mon Aug 26 10:55:52 2019 +0200
+
+ BUG/MEDIUM: listener/threads: fix an AB/BA locking issue in delete_listener()
+
+ The delete_listener() function takes the listener's lock before taking
+ the proto_lock, which is contrary to what other functions do, possibly
+ causing an AB/BA deadlock. In practice the two only places where both
+ are taken are during protocol_enable_all() and delete_listener(), the
+ former being used during startup and the latter during stop. In practice
+ during reload floods, it is technically possible for a thread to be
+ initializing the listeners while another one is stopping. While this
+ is too hard to trigger on 2.0 and above due to the synchronization of
+ all threads during startup, it's reasonably easy to do in 1.9 by having
+ hundreds of listeners, starting 64 threads and flooding them with reloads
+ like this :
+
+ $ while usleep 50000; do killall -USR2 haproxy; done
+
+ Usually in less than a minute, all threads will be deadlocked. The fix
+ consists in always taking the proto_lock before the listener lock. It
+ seems to be the only place where these two locks were reversed. This
+ fix needs to be backported to 2.0, 1.9, and 1.8.
+
+ (cherry picked from commit 6ee9f8df3bfbb811526cff3313da5758b1277bc6)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit b10c8d7641cc8ceae6fba4506b7f987d66109bd9)
+ [wt: adjusted context]
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+ (cherry picked from commit bf64d1021bd0db1f9892ec34473e34033cdb1dd9)
+ Signed-off-by: Willy Tarreau <w@1wt.eu>
+
+diff --git a/src/listener.c b/src/listener.c
+index 9832794d..92cc0f75 100644
+--- a/src/listener.c
++++ b/src/listener.c
+@@ -424,17 +424,17 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
+ */
+ void delete_listener(struct listener *listener)
+ {
++ HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
+ HA_SPIN_LOCK(LISTENER_LOCK, &listener->lock);
+ if (listener->state == LI_ASSIGNED) {
+ listener->state = LI_INIT;
+- HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
+ LIST_DEL(&listener->proto_list);
+ listener->proto->nb_listeners--;
+- HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
+ HA_ATOMIC_SUB(&jobs, 1);
+ HA_ATOMIC_SUB(&listeners, 1);
+ }
+ HA_SPIN_UNLOCK(LISTENER_LOCK, &listener->lock);
++ HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
+ }
+
+ /* This function is called on a read event from a listening socket, corresponding
+++ /dev/null
-commit f95cf6ad70565ee2322cf23bc519b7bb0b3831b2
-Author: Olivier Houchard <ohouchard@haproxy.com>
-Date: Tue Apr 30 13:38:02 2019 +0200
-
- MINOR: threads: Implement HA_ATOMIC_LOAD().
-
- The same way we have HA_ATOMIC_STORE(), implement HA_ATOMIC_LOAD().
-
- This should be backported to 1.8 and 1.9, as we need it for a bug fix
- in port ranges.
-
- (cherry picked from commit 9ce62b5498b27fbf4217d9c25779d5b2ceca23f2)
- Signed-off-by: Olivier Houchard <cognet@ci0.org>
- (cherry picked from commit 358c979611370fa2bc3b8e47ed50a325cf9126cf)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/common/hathreads.h b/include/common/hathreads.h
-index 8134839a..11d7cab6 100644
---- a/include/common/hathreads.h
-+++ b/include/common/hathreads.h
-@@ -62,6 +62,7 @@ enum { tid = 0 };
- *(val) = new; \
- __old_xchg; \
- })
-+#define HA_ATOMIC_LOAD(val) *(val)
- #define HA_ATOMIC_STORE(val, new) ({*(val) = new;})
- #define HA_ATOMIC_UPDATE_MAX(val, new) \
- ({ \
-@@ -203,6 +204,16 @@ static inline unsigned long thread_isolated()
- } while (!__sync_bool_compare_and_swap(__val_xchg, __old_xchg, __new_xchg)); \
- __old_xchg; \
- })
-+
-+#define HA_ATOMIC_LOAD(val) \
-+ ({ \
-+ typeof(*(val)) ret; \
-+ __sync_synchronize(); \
-+ ret = *(volatile typeof(val))val; \
-+ __sync_synchronize(); \
-+ ret; \
-+ })
-+
- #define HA_ATOMIC_STORE(val, new) \
- ({ \
- typeof((val)) __val_store = (val); \
-@@ -221,6 +232,8 @@ static inline unsigned long thread_isolated()
- #define HA_ATOMIC_OR(val, flags) __atomic_or_fetch(val, flags, __ATOMIC_SEQ_CST)
- #define HA_ATOMIC_XCHG(val, new) __atomic_exchange_n(val, new, __ATOMIC_SEQ_CST)
- #define HA_ATOMIC_STORE(val, new) __atomic_store_n(val, new, __ATOMIC_SEQ_CST)
-+#define HA_ATOMIC_LOAD(val) __atomic_load_n(val, __ATOMIC_SEQ_CST)
-+
- #endif
-
- #define HA_ATOMIC_UPDATE_MAX(val, new) \
+++ /dev/null
-commit 31470e2ba2aabb4c6340fbc15cb5486ceb8c69c8
-Author: Olivier Houchard <ohouchard@haproxy.com>
-Date: Mon Apr 29 18:52:06 2019 +0200
-
- BUG/MEDIUM: port_range: Make the ring buffer lock-free.
-
- Port range uses a ring buffer, and unfortunately, when making haproxy
- multithreaded, it's been overlooked, and the ring buffer is not thread-safe.
- When specifying a source range, 2 or more threads could pick the same
- port, and of course only one of them could use the port, the others would
- always fail the connection.
- To fix this, make it a lock-free ring buffer. This is easier than usual
- because we know the ring buffer can never be full.
-
- This should be backported to 1.8 and 1.9.
-
- (cherry picked from commit 07425de71777b688e77a9c70a7088c13e66e41e9)
- Signed-off-by: Olivier Houchard <cognet@ci0.org>
- (cherry picked from commit bffb51147a4a5939e344b3c838628f9a944febef)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/proto/port_range.h b/include/proto/port_range.h
-index 8c63faca..f7e3f1d5 100644
---- a/include/proto/port_range.h
-+++ b/include/proto/port_range.h
-@@ -24,18 +24,22 @@
-
- #include <types/port_range.h>
-
-+#define GET_NEXT_OFF(range, off) ((off) == (range)->size - 1 ? 0 : (off) + 1)
-+
- /* return an available port from range <range>, or zero if none is left */
- static inline int port_range_alloc_port(struct port_range *range)
- {
- int ret;
-+ int get;
-+ int put;
-
-- if (!range->avail)
-- return 0;
-- ret = range->ports[range->get];
-- range->get++;
-- if (range->get >= range->size)
-- range->get = 0;
-- range->avail--;
-+ get = HA_ATOMIC_LOAD(&range->get);
-+ do {
-+ put = HA_ATOMIC_LOAD(&range->put_t);
-+ if (unlikely(put == get))
-+ return 0;
-+ ret = range->ports[get];
-+ } while (!(HA_ATOMIC_CAS(&range->get, &get, GET_NEXT_OFF(range, get))));
- return ret;
- }
-
-@@ -45,14 +49,28 @@ static inline int port_range_alloc_port(struct port_range *range)
- */
- static inline void port_range_release_port(struct port_range *range, int port)
- {
-+ int put;
-+
- if (!port || !range)
- return;
-
-- range->ports[range->put] = port;
-- range->avail++;
-- range->put++;
-- if (range->put >= range->size)
-- range->put = 0;
-+ put = range->put_h;
-+ /* put_h is reserved for producers, so that they can each get a
-+ * free slot, put_t is what is used by consumers to know if there's
-+ * elements available or not
-+ */
-+ /* First reserve or slot, we know the ring buffer can't be full,
-+ * as we will only ever release port we allocated before
-+ */
-+ while (!(HA_ATOMIC_CAS(&range->put_h, &put, GET_NEXT_OFF(range, put))));
-+ HA_ATOMIC_STORE(&range->ports[put], port);
-+ /* Wait until all the threads that got a slot before us are done */
-+ while ((volatile int)range->put_t != put)
-+ __ha_compiler_barrier();
-+ /* Let the world know we're done, and any potential consumer they
-+ * can use that port.
-+ */
-+ HA_ATOMIC_STORE(&range->put_t, GET_NEXT_OFF(range, put));
- }
-
- /* return a new initialized port range of N ports. The ports are not
-@@ -62,8 +80,10 @@ static inline struct port_range *port_range_alloc_range(int n)
- {
- struct port_range *ret;
- ret = calloc(1, sizeof(struct port_range) +
-- n * sizeof(((struct port_range *)0)->ports[0]));
-- ret->size = ret->avail = n;
-+ (n + 1) * sizeof(((struct port_range *)0)->ports[0]));
-+ ret->size = n + 1;
-+ /* Start at the first free element */
-+ ret->put_h = ret->put_t = n;
- return ret;
- }
-
-diff --git a/include/types/port_range.h b/include/types/port_range.h
-index 1d010f77..33455d2d 100644
---- a/include/types/port_range.h
-+++ b/include/types/port_range.h
-@@ -25,8 +25,7 @@
- #include <netinet/in.h>
-
- struct port_range {
-- int size, get, put; /* range size, and get/put positions */
-- int avail; /* number of available ports left */
-+ int size, get, put_h, put_t; /* range size, and get/put positions */
- uint16_t ports[0]; /* array of <size> ports, in host byte order */
- };
-
--- /dev/null
+commit ba3abeda541ffe93fd528e9bc8701d4faadfb680
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date: Wed Sep 4 09:39:42 2019 +0200
+
+ BUG/MEDIUM: proto-http: Always start the parsing if there is no outgoing data
+
+ When we are waiting for a request or a response, if the channel's buffer is not
+ rewritable (the reservce is not fully free), nothing is done and we wait to have
+ a rewritable buffer. It was an old implicit assumption of HTTP analyzers. On old
+ versions, at this stage, if a buffer was not rewritable, it meant some outgoing
+ data were pending to be sent.
+
+ On recent versions, it should not happen because all outgoing data are sent
+ before starting the analysis of the next transaction. But the applets may be
+ lead to use the reserve. For instance, the cache applet adds the header "Age" to
+ cached responses. It may use the reserve to do so if the size of the response
+ headers is huge. So, in such case, the implicit assumption of a no rewritable
+ buffer because of output data is wrong. But the message analysis remains
+ blocked, sometime infinitely depending on circumstances.
+
+ To fix the bug and to avoid any ambiguity, we now also check if there are some
+ outgoing data when the buffer is not rewritable to postpone the message
+ analysis. In fact, this code may probably be removed because it should never
+ happen. But I prefer to be conservative here and don't introduce a bug because of
+ an unknown/unexpected hidden corner case. Anyway, it is not a big deal because
+ all legacy HTTP code is removed in the 2.1.
+
+ This is a direct commit to the 2.0 branch, as the problem doesn't exist in
+ master. It must be backported at least to 1.9 and 1.8 because of the cache. But
+ it may be also backported to all stable versions.
+
+ This patch should partly fix the github issue #233.
+
+ (cherry picked from commit 3d36d4e720a76a12c7f6cd64c7971237d7d92d78)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+ (cherry picked from commit d09d66853a3700d2b9261c02e1027d13b4420f5b)
+ Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index c64ba0ea..411eb698 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -1633,7 +1633,7 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit)
+ */
+ if (buffer_not_empty(req->buf) && msg->msg_state < HTTP_MSG_ERROR) {
+ if (txn->flags & TX_NOT_FIRST) {
+- if (unlikely(!channel_is_rewritable(req))) {
++ if (unlikely(!channel_is_rewritable(req) && req->buf->o)) {
+ if (req->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
+ goto failed_keep_alive;
+ /* some data has still not left the buffer, wake us once that's done */
+@@ -5102,7 +5102,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
+ * data later, which is much more complicated.
+ */
+ if (buffer_not_empty(rep->buf) && msg->msg_state < HTTP_MSG_ERROR) {
+- if (unlikely(!channel_is_rewritable(rep))) {
++ if (unlikely(!channel_is_rewritable(rep) && rep->buf->o)) {
+ /* some data has still not left the buffer, wake us once that's done */
+ if (rep->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
+ goto abort_response;
+++ /dev/null
-commit ef9cafc46c13eea2db65152e452607a6566cbeac
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Thu May 16 10:07:30 2019 +0200
-
- BUG/MINOR: http_fetch: Rely on the smp direction for "cookie()" and "hdr()"
-
- A regression was introduced in the commit 89dc49935 ("BUG/MAJOR: http_fetch: Get
- the channel depending on the keyword used") on the samples "cookie()" and
- "hdr()". Unlike other samples manipulating the HTTP headers, these ones depend
- on the sample direction. To fix the bug, these samples use now their own
- functions. Depending on the sample direction, they call smp_fetch_cookie() and
- smp_fetch_hdr() with the appropriate keyword.
-
- Thanks to Yves Lafon to report this issue.
-
- This patch must be backported wherever the commit 89dc49935 was backported. For
- now, 1.9 and 1.8.
-
- (cherry picked from commit c1f40dd4920050ec5a83b2a5d22a3eb4e4be425a)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 5eaf770abfce56951202cb1ea55a968f5ec8be71)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/proto_http.c b/src/proto_http.c
-index 556cabad..32aeef2d 100644
---- a/src/proto_http.c
-+++ b/src/proto_http.c
-@@ -10218,6 +10218,17 @@ smp_fetch_hdr(const struct arg *args, struct sample *smp, const char *kw, void *
- return 0;
- }
-
-+/* Same than smp_fetch_hdr() but only relies on the sample direction to choose
-+ * the right channel. So instead of duplicating the code, we just change the
-+ * keyword and then fallback on smp_fetch_hdr().
-+ */
-+static int
-+smp_fetch_chn_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
-+{
-+ kw = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ ? "req.hdr" : "res.hdr");
-+ return smp_fetch_hdr(args, smp, kw, private);
-+}
-+
- /* 6. Check on HTTP header count. The number of occurrences is returned.
- * Accepts exactly 1 argument of type string.
- */
-@@ -10935,6 +10946,17 @@ int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw,
- return found;
- }
-
-+/* Same than smp_fetch_cookie() but only relies on the sample direction to
-+ * choose the right channel. So instead of duplicating the code, we just change
-+ * the keyword and then fallback on smp_fetch_cookie().
-+ */
-+static int
-+smp_fetch_chn_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
-+{
-+ kw = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ ? "req.cook" : "res.cook");
-+ return smp_fetch_cookie(args, smp, kw, private);
-+}
-+
- /* Iterate over all cookies present in a request to count how many occurrences
- * match the name in args and args->data.str.len. If <multi> is non-null, then
- * multiple cookies may be parsed on the same line. The returned sample is of
-@@ -12855,7 +12877,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
- * for ACL compatibility only.
- */
- { "cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
-- { "cookie", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
-+ { "cookie", smp_fetch_chn_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
- { "cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
- { "cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
-
-@@ -12863,7 +12885,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
- * only here to match the ACL's name, are request-only and are used for
- * ACL compatibility only.
- */
-- { "hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
-+ { "hdr", smp_fetch_chn_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
- { "hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV },
- { "hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV },
- { "hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRQHV },
--- /dev/null
+--- a/src/ssl_sock.c
++++ b/src/ssl_sock.c
+@@ -39,6 +39,7 @@
+ #include <netdb.h>
+ #include <netinet/tcp.h>
+
++#include <openssl/bn.h>
+ #include <openssl/crypto.h>
+ #include <openssl/ssl.h>
+ #include <openssl/x509.h>
+@@ -60,6 +61,17 @@
+ #include <openssl/async.h>
+ #endif
+
++#ifndef OPENSSL_VERSION
++#define OPENSSL_VERSION SSLEAY_VERSION
++#define OpenSSL_version(x) SSLeay_version(x)
++#define OpenSSL_version_num SSLeay
++#endif
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#define X509_getm_notBefore X509_get_notBefore
++#define X509_getm_notAfter X509_get_notAfter
++#endif
++
+ #include <import/lru.h>
+ #include <import/xxhash.h>
+
+@@ -217,7 +229,7 @@ static struct {
+ .capture_cipherlist = 0,
+ };
+
+-#ifdef USE_THREAD
++#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
+
+ static HA_RWLOCK_T *ssl_rwlocks;
+
+@@ -1716,8 +1728,8 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL
+ ASN1_INTEGER_set(X509_get_serialNumber(newcrt), HA_ATOMIC_ADD(&ssl_ctx_serial, 1));
+
+ /* Set duration for the certificate */
+- if (!X509_gmtime_adj(X509_get_notBefore(newcrt), (long)-60*60*24) ||
+- !X509_gmtime_adj(X509_get_notAfter(newcrt),(long)60*60*24*365))
++ if (!X509_gmtime_adj(X509_getm_notBefore(newcrt), (long)-60*60*24) ||
++ !X509_gmtime_adj(X509_getm_notAfter(newcrt),(long)60*60*24*365))
+ goto mkcert_error;
+
+ /* set public key in the certificate */
+@@ -6299,7 +6311,7 @@ smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char
+ goto out;
+
+ smp_trash = get_trash_chunk();
+- if (ssl_sock_get_time(X509_get_notAfter(crt), smp_trash) <= 0)
++ if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
+ goto out;
+
+ smp->data.u.str = *smp_trash;
+@@ -6399,7 +6411,7 @@ smp_fetch_ssl_x_notbefore(const struct a
+ goto out;
+
+ smp_trash = get_trash_chunk();
+- if (ssl_sock_get_time(X509_get_notBefore(crt), smp_trash) <= 0)
++ if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
+ goto out;
+
+ smp->data.u.str = *smp_trash;
+@@ -8977,7 +8989,9 @@ static void __ssl_sock_init(void)
+ #endif
+
+ xprt_register(XPRT_SSL, &ssl_sock);
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_library_init();
++#endif
+ #if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION))
+ cm = SSL_COMP_get_compression_methods();
+ i = sk_SSL_COMP_num(cm);
+@@ -8986,7 +9000,7 @@ static void __ssl_sock_init(void)
+ }
+ #endif
+
+-#ifdef USE_THREAD
++#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ ssl_locking_init();
+ #endif
+ #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+@@ -9015,8 +9029,8 @@ static void __ssl_sock_init(void)
+ #else /* OPENSSL_IS_BORINGSSL */
+ OPENSSL_VERSION_TEXT
+ "\nRunning on OpenSSL version : %s%s",
+- SSLeay_version(SSLEAY_VERSION),
+- ((OPENSSL_VERSION_NUMBER ^ SSLeay()) >> 8) ? " (VERSIONS DIFFER!)" : "");
++ OpenSSL_version(OPENSSL_VERSION),
++ ((OPENSSL_VERSION_NUMBER ^ OpenSSL_version_num()) >> 8) ? " (VERSIONS DIFFER!)" : "");
+ #endif
+ memprintf(&ptr, "%s\nOpenSSL library supports TLS extensions : "
+ #if OPENSSL_VERSION_NUMBER < 0x00907000L
+@@ -9107,12 +9121,14 @@ static void __ssl_sock_deinit(void)
+ }
+ #endif
+
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ ERR_remove_state(0);
+ ERR_free_strings();
+
+ EVP_cleanup();
++#endif
+
+-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
++#if OPENSSL_VERSION_NUMBER >= 0x00907000L && OPENSSL_VERSION_NUMBER < 0x10100000L
+ CRYPTO_cleanup_all_ex_data();
+ #endif
+ }
+++ /dev/null
-commit b50e7fe5e9ae7e8670a467fdd7ece2d08fc02809
-Author: Willy Tarreau <w@1wt.eu>
-Date: Wed May 22 20:07:45 2019 +0200
-
- BUG/MEDIUM: dns: make the port numbers unsigned
-
- Mustafa Yildirim reported in Discourse that ports >32767 advertised
- in SRV records are wrong. Given the high value they definitely
- correspond to a sign extension of a negative number. The cause was
- indeed that the port is declared as a signed int in the dns_answer_item
- structure, and Lukas confirmed in github issue #103 that turning it to
- unsigned addresses the issue.
-
- It is worth noting that there are other such fields in this structure
- that don't look right (ttl, priority, class, type) and that someone
- should audit this part to be certain they are properly typed.
-
- This fix must be backported to 1.9 and likely to 1.8 as well.
-
- (cherry picked from commit d1f56c9a0110805c4a5f3afba2990556cb74ec8b)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 01ceb8a9fb0caecb20a12cc6763230cfc9895de5)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/types/dns.h b/include/types/dns.h
-index e8ab9f06..e2d98169 100644
---- a/include/types/dns.h
-+++ b/include/types/dns.h
-@@ -144,7 +144,7 @@ struct dns_answer_item {
- int32_t ttl; /* response TTL */
- int16_t priority; /* SRV type priority */
- uint16_t weight; /* SRV type weight */
-- int16_t port; /* SRV type port */
-+ uint16_t port; /* SRV type port */
- uint16_t data_len; /* number of bytes in target below */
- struct sockaddr address; /* IPv4 or IPv6, network format */
- char target[DNS_MAX_NAME_SIZE+1]; /* Response data: SRV or CNAME type target */
+++ /dev/null
-commit 89ff157c3262c8493ed48e6ac48f614791f446f8
-Author: Christopher Faulet <cfaulet@haproxy.com>
-Date: Thu May 23 22:47:48 2019 +0200
-
- BUG/MEDIUM: spoe: Don't use the SPOE applet after releasing it
-
- In spoe_release_appctx(), the SPOE applet may be used after it was released to
- get its exit status code. Of course, HAProxy crashes when this happens.
-
- This patch must be backported to 1.9 and 1.8.
-
- (cherry picked from commit 55ae8a64e4e1175063463921375b279c31bbc6a4)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit df29d11f522044217ea7c1373f494c2a36515b31)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/flt_spoe.c b/src/flt_spoe.c
-index 66d8b045..aeb1fde7 100644
---- a/src/flt_spoe.c
-+++ b/src/flt_spoe.c
-@@ -1292,11 +1292,6 @@ spoe_release_appctx(struct appctx *appctx)
- task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
- }
-
-- /* Release allocated memory */
-- spoe_release_buffer(&spoe_appctx->buffer,
-- &spoe_appctx->buffer_wait);
-- pool_free(pool_head_spoe_appctx, spoe_appctx);
--
- if (!LIST_ISEMPTY(&agent->rt[tid].applets))
- goto end;
-
-@@ -1317,6 +1312,11 @@ spoe_release_appctx(struct appctx *appctx)
- }
-
- end:
-+ /* Release allocated memory */
-+ spoe_release_buffer(&spoe_appctx->buffer,
-+ &spoe_appctx->buffer_wait);
-+ pool_free(pool_head_spoe_appctx, spoe_appctx);
-+
- /* Update runtinme agent info */
- agent->rt[tid].frame_size = agent->max_frame_size;
- list_for_each_entry(spoe_appctx, &agent->rt[tid].applets, list)
+++ /dev/null
-commit 5aa7b32a94ad7ac38f465f0de279f09ff6d529d3
-Author: Michael Prokop <haproxy.org@michael-prokop.at>
-Date: Fri May 24 10:25:45 2019 +0200
-
- DOC: fix typos
-
- s/accidently/accidentally/
- s/any ot these messages/any of theses messages/
- s/catched/caught/
- s/completly/completely/
- s/convertor/converter/
- s/desribing/describing/
- s/developper/developer/
- s/eventhough/even though/
- s/exectution/execution/
- s/functionnality/functionality/
- s/If it receive a/If it receives a/
- s/In can even/It can even/
- s/informations/information/
- s/it will be remove /it will be removed /
- s/langage/language/
- s/mentionned/mentioned/
- s/negociated/negotiated/
- s/Optionnaly/Optionally/
- s/ouputs/outputs/
- s/outweights/outweighs/
- s/ressources/resources/
-
- (cherry picked from commit 4438c6061d5a2ffd5b4251027038181af9b8dc22)
- [wt: removed the wurfl+da notes as well as the part on peers/server]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit a73e4f3d7a617a51551fffd80c5dbddee81e3aaf)
- [wt: removed a few other keywords like ssl_bc_alpn and show peers]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
-
-diff --git a/doc/DeviceAtlas-device-detection.txt b/doc/DeviceAtlas-device-detection.txt
-index 4ecb44a4..144ee318 100644
---- a/doc/DeviceAtlas-device-detection.txt
-+++ b/doc/DeviceAtlas-device-detection.txt
-@@ -39,7 +39,7 @@ All HTTP headers via the sample / fetch
-
- http-request set-header X-DeviceAtlas-Data %[da-csv-fetch(primaryHardwareType,osName,osVersion,browserName,browserVersion,browserRenderingEngine)]
-
--Single HTTP header (e.g. User-Agent) via the convertor
-+Single HTTP header (e.g. User-Agent) via the converter
-
- http-request set-header X-DeviceAtlas-Data %[req.fhdr(User-Agent),da-csv-conv(primaryHardwareType,osName,osVersion,browserName,browserVersion,browserRenderingEngine)]
-
-diff --git a/doc/SPOE.txt b/doc/SPOE.txt
-index dd36d43a..9602df95 100644
---- a/doc/SPOE.txt
-+++ b/doc/SPOE.txt
-@@ -96,7 +96,7 @@ for several engines. If no name is provided, the SPOE configuration must not
- contain any scope directive.
-
- We use a separate configuration file on purpose. By commenting SPOE filter
--line, you completly disable the feature, including the parsing of sections
-+line, you completely disable the feature, including the parsing of sections
- reserved to SPOE. This is also a way to keep the HAProxy configuration clean.
-
- A SPOE configuration file must contains, at least, the SPOA configuration
-@@ -272,7 +272,7 @@ option set-on-error <var name>
-
- * 1 a timeout occurred during the event processing.
-
-- * 2 an error was triggered during the ressources allocation.
-+ * 2 an error was triggered during the resources allocation.
-
- * 3 the frame payload exceeds the frame size and it cannot be
- fragmented.
-@@ -923,7 +923,7 @@ For more information about known errors, see section "Errors & timeouts"
- -------------------------------
-
- If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame
--is sent, with information desribing the error. such frame is also sent in reply
-+is sent, with information describing the error. such frame is also sent in reply
- to a HAPROXY-DISCONNECT. The agent must close the socket just after sending
- this frame.
-
-diff --git a/doc/coding-style.txt b/doc/coding-style.txt
-index 5f252ed0..9f1bd79e 100644
---- a/doc/coding-style.txt
-+++ b/doc/coding-style.txt
-@@ -520,7 +520,7 @@ Wrong :
- | bit = ! ! (~len++ ^ - (unsigned char) * x) ;
-
- Note that "sizeof" is a unary operator which is sometimes considered as a
--langage keyword, but in no case it is a function. It does not require
-+language keyword, but in no case it is a function. It does not require
- parenthesis so it is sometimes followed by spaces and sometimes not when
- there are no parenthesis. Most people do not really care as long as what
- is written is unambiguous.
-@@ -814,7 +814,7 @@ common to see such a thing :
- This is wrong. The man page says that -1 is returned if an error occurred. It
- does not suggest that any other negative value will be an error. It is possible
- that a few such issues have been left in existing code. They are bugs for which
--fixes are accepted, eventhough they're currently harmless since open() is not
-+fixes are accepted, even though they're currently harmless since open() is not
- known for returning negative values at the moment.
-
-
-diff --git a/doc/configuration.txt b/doc/configuration.txt
-index 863508f5..e044639a 100644
---- a/doc/configuration.txt
-+++ b/doc/configuration.txt
-@@ -3051,7 +3051,7 @@ cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
-
- already have a cookie that would have permitted it to access this
- server. When used without the "preserve" option, if the server
-- emits a cookie with the same name, it will be remove before
-+ emits a cookie with the same name, it will be removed before
- processing. For this reason, this mode can be used to upgrade
- existing configurations running in the "rewrite" mode. The cookie
- will only be a session cookie and will not be stored on the
-@@ -4786,7 +4786,7 @@ http-reuse { never | safe | aggressive | always }
- proving that the server correctly supports connection reuse.
- It should only be used when it's sure that the client can
- retry a failed request once in a while and where the benefit
-- of aggressive connection reuse significantly outweights the
-+ of aggressive connection reuse significantly outweighs the
- downsides of rare connection failures.
-
- - "always" : this mode is only recommended when the path to the server is
-diff --git a/doc/intro.txt b/doc/intro.txt
-index 7ad92db0..864fb8d6 100644
---- a/doc/intro.txt
-+++ b/doc/intro.txt
-@@ -1481,7 +1481,7 @@ they are mentioned here even if not directly related to HAProxy.
-
- Apache is the de-facto standard HTTP server. It's a very complete and modular
- project supporting both file serving and dynamic contents. It can serve as a
--frontend for some application servers. In can even proxy requests and cache
-+frontend for some application servers. It can even proxy requests and cache
- responses. In all of these use cases, a front load balancer is commonly needed.
- Apache can work in various modes, some being heavier than others. Certain
- modules still require the heavier pre-forked model and will prevent Apache from
-diff --git a/doc/lua.txt b/doc/lua.txt
-index 7b257ad8..2e266b03 100644
---- a/doc/lua.txt
-+++ b/doc/lua.txt
-@@ -412,7 +412,7 @@ The max amount of memory is configured with the option:
- tune.lua.maxmem
-
- As many other script languages, Lua uses a garbage collector for reusing its
--memory. The Lua developper can work without memory preoccupation. Usually, the
-+memory. The Lua developer can work without memory preoccupation. Usually, the
- garbage collector is controlled by the Lua core, but sometimes it will be useful
- to run when the user/developer requires. So the garbage collector can be called
- from C part or Lua part.
-@@ -885,7 +885,7 @@ The task entry point
-
- The function "core.register_task(fcn)" executes once the function "fcn" when the
- scheduler starts. This way is used for executing background task. For example,
--you can use this functionnality for periodically checking the health of another
-+you can use this functionality for periodically checking the health of another
- service, and giving the result to each proxy needing it.
-
- The task is started once, if you want periodic actions, you can use the
-diff --git a/doc/management.txt b/doc/management.txt
-index 1b41558a..8fdea722 100644
---- a/doc/management.txt
-+++ b/doc/management.txt
-@@ -1634,7 +1634,7 @@ set rate-limit ssl-sessions global <value>
-
- set server <backend>/<server> addr <ip4 or ip6 address> [port <port>]
- Replace the current IP address of a server by the one provided.
-- Optionnaly, the port can be changed using the 'port' parameter.
-+ Optionally, the port can be changed using the 'port' parameter.
- Note that changing the port also support switching from/to port mapping
- (notation with +X or -Y), only if a port is configured for the health check.
-
-diff --git a/doc/netscaler-client-ip-insertion-protocol.txt b/doc/netscaler-client-ip-insertion-protocol.txt
-index 559d98a8..dc64327a 100644
---- a/doc/netscaler-client-ip-insertion-protocol.txt
-+++ b/doc/netscaler-client-ip-insertion-protocol.txt
-@@ -1,4 +1,4 @@
--When NetScaler application switch is used as L3+ switch, informations
-+When NetScaler application switch is used as L3+ switch, information
- regarding the original IP and TCP headers are lost as a new TCP
- connection is created between the NetScaler and the backend server.
-
-diff --git a/doc/peers-v2.0.txt b/doc/peers-v2.0.txt
-index a7f70dcc..02914743 100644
---- a/doc/peers-v2.0.txt
-+++ b/doc/peers-v2.0.txt
-@@ -275,11 +275,11 @@ if no available remote peers are found.
-
- The chosen remote peer will push its all known data ending with a Resync Finished Message or a Resync Partial Message (if it it does not consider itself as full updated).
-
--If it receive a Resync Finished Message it will consider itself as fully updated and stops to ask for resync.
-+If it receives a Resync Finished Message it will consider itself as fully updated and stops to ask for resync.
-
--If it receive a Resync Partial Message, the current peer will be flagged to anymore be requested and any other connected peer will be randomly chosen for a resync request (5s).
-+If it receives a Resync Partial Message, the current peer will be flagged to anymore be requested and any other connected peer will be randomly chosen for a resync request (5s).
-
--If the session is broken before receiving any ot these messages any other connected peer will be randomly chosen for a resync request (5s).
-+If the session is broken before receiving any of these messages any other connected peer will be randomly chosen for a resync request (5s).
-
- If the timeout expire, the process will consider itself as fully updated
-
-diff --git a/doc/proxy-protocol.txt b/doc/proxy-protocol.txt
-index 4969180a..52d7bc71 100644
---- a/doc/proxy-protocol.txt
-+++ b/doc/proxy-protocol.txt
-@@ -561,7 +561,7 @@ Contains the host name value passed by the client, as an UTF8-encoded string.
- In case of TLS being used on the client connection, this is the exact copy of
- the "server_name" extension as defined by RFC3546 [10], section 3.1, often
- referred to as "SNI". There are probably other situations where an authority
--can be mentionned on a connection without TLS being involved at all.
-+can be mentioned on a connection without TLS being involved at all.
-
-
- 2.2.3. PP2_TYPE_CRC32C
-diff --git a/doc/regression-testing.txt b/doc/regression-testing.txt
-new file mode 100644
-index 00000000..320c51cd
---- /dev/null
-+++ b/doc/regression-testing.txt
-@@ -0,0 +1,706 @@
-+ +---------------------------------------+
-+ | HAProxy regression testing with vtest |
-+ +---------------------------------------+
-+
-+
-+The information found in this file are a short starting guide to help you to
-+write VTC (Varnish Test Case) scripts (or VTC files) for haproxy regression testing.
-+Such VTC files are currently used to test Varnish cache application developed by
-+Poul-Henning Kamp. A very big thanks you to him for having helped you to add
-+our haproxy C modules to vtest tool. Note that vtest was formally developed for
-+varnish cache reg testing and was named varnishtest. vtest is an haproxy specific
-+version of varnishtest program which reuses the non varnish cache specific code.
-+
-+A lot of general information about how to write VTC files may be found in 'man/vtc.7'
-+manual of varnish cache sources directory or directly on the web here:
-+
-+ https://varnish-cache.org/docs/trunk/reference/vtc.html
-+
-+It is *highly* recommended to read this manual before asking to haproxy ML. This
-+documentation only deals with the vtest support for haproxy.
-+
-+
-+vtest installation
-+------------------------
-+
-+To use vtest you will have to download and compile the recent vtest
-+sources found at https://github.com/vtest/VTest.
-+
-+To compile vtest:
-+
-+ $ cd VTest
-+ $ make vtest
-+
-+Note that varnishtest may be also compiled but not without the varnish cache
-+sources already compiled:
-+
-+ $ VARNISH_SRC=<...> make varnishtest
-+
-+After having compiled these sources, the vtest executable location is at the
-+root of the vtest sources directory.
-+
-+
-+vtest execution
-+---------------------
-+
-+vtest is able to search for the haproxy executable file it is supposed to
-+launch thanks to the PATH environment variable. To force the executable to be used by
-+vtest, the HAPROXY_PROGRAM environment variable for vtest may be
-+typically set as follows:
-+
-+ $ HAPROXY_PROGRAM=~/srcs/haproxy/haproxy vtest ...
-+
-+vtest program comes with interesting options. The most interesting are:
-+
-+ -t Timeout in seconds to abort the test if some launched program
-+ -v By default, vtest does not dump the outputs of processus it launched
-+ when the test passes. With this option the outputs are dumped even
-+ when the test passes.
-+ -L to always keep the temporary VTC directories.
-+ -l to keep the temporary VTC directories only when the test fails.
-+
-+About haproxy, when launched by vtest, -d option is enabled by default.
-+
-+
-+How to write VTC files
-+----------------------
-+
-+A VTC file must start with a "varnishtest" or "vtest" command line followed by a
-+descriptive line enclosed by double quotes. This is not specific to the VTC files
-+for haproxy.
-+
-+The VTC files for haproxy must also contain a "feature ignore_unknown_macro" line
-+if any macro is used for haproxy in this file. This is due to the fact that
-+vtest parser code for haproxy commands generates macros the vtest
-+parser code for varnish cache has no knowledge of. This line prevents vtest from
-+failing in such cases. As a "cli" macro automatically generated, this
-+"feature ignore_unknown_macro" is mandatory for each VTC file for haproxy.
-+
-+To make vtest capable of testing haproxy, two new VTC commands have been
-+implemented: "haproxy" and "syslog". "haproxy" is used to start haproxy processus.
-+"syslog" is used to start syslog servers (at this time, only used by haproxy).
-+
-+As haproxy cannot work without configuration file, a VTC file for haproxy must
-+embed the configuration files contents for the haproxy instances it declares.
-+This may be done using the following intuitive syntax construction: -conf {...}.
-+Here -conf is an argument of "haproxy" VTC command to declare the configuration
-+file of the haproxy instances it also declares (see "Basic HAProxy test" VTC file
-+below).
-+
-+As for varnish VTC files, the parser of VTC files for haproxy automatically
-+generates macros for the declared frontends to be reused by the clients later
-+in the script, so after having written the "haproxy" command sections.
-+The syntax "fd@${my_frontend_fd_name}" must be used to bind the frontend
-+listeners to localhost address and random ports (see "Environment variables"
-+section of haproxy documentation). This is mandatory.
-+
-+Each time the haproxy command parser finds a "fd@${xyz}" string in a 'ABC'
-+"haproxy" command section, it generates three macros: 'ABC_xyz_addr', 'ABC_xyz_port'
-+and 'ABC_xyz_sock', with 'ABC_xyz_sock' being resolved as 'ABC_xyz_addr
-+ABC_xyz_port' typically used by clients -connect parameter.
-+
-+Each haproxy instance works in their own temporary working directories located
-+at '/tmp/vtc.<varnitest PID>.XXXXXXXX/<haproxy_instance_name>' (with XXXXXXXX
-+a random 8 digits hexadecimal integer. This is in this temporary directory that
-+the configuration file is temporarily written.
-+
-+A 'stats.sock' UNIX socket is also created in this directory. There is no need
-+to declare such stats sockets in the -conf {...} section. The name of the parent
-+directory of the haproxy instances working directories is stored in 'tmpdir'. In
-+fact this is the working directory of the current vtest processus.
-+
-+There also exists 'testdir' macro which is the parent directory of the VTC file.
-+It may be useful to use other files located in the same directory than the current
-+VTC file.
-+
-+
-+
-+VTC file examples
-+-----------------
-+
-+The following first VTC file is a real regression test case file for a bug which has
-+been fixed by 84c844e commit. We declare a basic configuration for a 'h1' haproxy
-+instance.
-+
-+ varnishtest "SPOE bug: missing configuration file"
-+
-+ #commit 84c844eb12b250aa86f2aadaff77c42dfc3cb619
-+ #Author: Christopher Faulet <cfaulet@haproxy.com>
-+ #Date: Fri Mar 23 14:37:14 2018 +0100
-+
-+ # BUG/MINOR: spoe: Initialize variables used during conf parsing before any check
-+
-+ # Some initializations must be done at the beginning of parse_spoe_flt to avoid
-+ # segmentaion fault when first errors are caught, when the "filter spoe" line is
-+ # parsed.
-+
-+ haproxy h1 -conf-BAD {} {
-+ defaults
-+ timeout connect 5000ms
-+ timeout client 50000ms
-+ timeout server 50000ms
-+
-+ frontend my-front
-+ filter spoe
-+ }
-+
-+
-+-conf-BAD haproxy command argument is used. Its role it to launch haproxy with
-+-c option (configuration file checking) and check that 'h1' exit(3) with 1 as
-+status. Here is the output when running this VTC file:
-+
-+
-+ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy
-+ **** top 0.0 extmacro def localhost=127.0.0.1
-+ **** top 0.0 extmacro def bad_backend=127.0.0.1 39564
-+ **** top 0.0 extmacro def bad_ip=192.0.2.255
-+ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy
-+ **** top 0.0 macro def tmpdir=/tmp/vtc.6377.64329194
-+ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc starting
-+ ** top 0.0 === varnishtest "SPOE bug: missing configuration file"
-+ * top 0.0 TEST SPOE bug: missing configuration file
-+ ** top 0.0 === haproxy h1 -conf-BAD {} {
-+ **** h1 0.0 conf| global
-+ **** h1 0.0 conf|\tstats socket /tmp/vtc.6377.64329194/h1/stats.sock level admin mode 600
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf|\tdefaults
-+ **** h1 0.0 conf| timeout connect 5000ms
-+ **** h1 0.0 conf| timeout client 50000ms
-+ **** h1 0.0 conf| timeout server 50000ms
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf|\tfrontend my-front
-+ **** h1 0.0 conf|\t\tfilter spoe
-+ **** h1 0.0 conf|
-+ ** h1 0.0 haproxy_start
-+ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 1
-+ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -c -f /tmp/vtc.6377.64329194/h1/cfg
-+ **** h1 0.0 XXX 5 @277
-+ *** h1 0.0 PID: 6395
-+ **** h1 0.0 macro def h1_pid=6395
-+ **** h1 0.0 macro def h1_name=/tmp/vtc.6377.64329194/h1
-+ ** h1 0.0 Wait
-+ ** h1 0.0 Stop HAproxy pid=6395
-+ **** h1 0.0 STDOUT poll 0x10
-+ ** h1 0.0 WAIT4 pid=6395 status=0x008b (user 0.000000 sys 0.000000)
-+ * h1 0.0 Expected exit: 0x1 signal: 0 core: 0
-+ ---- h1 0.0 Bad exit status: 0x008b exit 0x0 signal 11 core 128
-+ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc
-+ ** h1 0.0 Reset and free h1 haproxy 6395
-+ ** h1 0.0 Wait
-+ ---- h1 0.0 Assert error in haproxy_wait(), vtc_haproxy.c line 326: Condition(*(&h->fds[1]) >= 0) not true.
-+
-+ * top 0.0 failure during reset
-+ # top TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc FAILED (0.008) exit=2
-+
-+
-+'h1' exited with (128 + 11) status and a core file was produced in
-+/tmp/vtc.6377.64329194/h1 directory.
-+With the patch provided by 84c844e commit, varnishtest makes this VTC file pass
-+as expected (verbose mode execution):
-+
-+ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy
-+ **** top 0.0 extmacro def localhost=127.0.0.1
-+ **** top 0.0 extmacro def bad_backend=127.0.0.1 42264
-+ **** top 0.0 extmacro def bad_ip=192.0.2.255
-+ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy
-+ **** top 0.0 macro def tmpdir=/tmp/vtc.25540.59b6ec5d
-+ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc starting
-+ ** top 0.0 === varnishtest "SPOE bug: missing configuration file"
-+ * top 0.0 TEST SPOE bug: missing configuration file
-+ ** top 0.0 === haproxy h1 -conf-BAD {} {
-+ **** h1 0.0 conf| global
-+ **** h1 0.0 conf|\tstats socket /tmp/vtc.25540.59b6ec5d/h1/stats.sock level admin mode 600
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf|\tdefaults
-+ **** h1 0.0 conf| timeout connect 5000ms
-+ **** h1 0.0 conf| timeout client 50000ms
-+ **** h1 0.0 conf| timeout server 50000ms
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf|\tfrontend my-front
-+ **** h1 0.0 conf|\t\tfilter spoe
-+ **** h1 0.0 conf|
-+ ** h1 0.0 haproxy_start
-+ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 1
-+ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -c -f /tmp/vtc.25540.59b6ec5d/h1/cfg
-+ **** h1 0.0 XXX 5 @277
-+ *** h1 0.0 PID: 25558
-+ **** h1 0.0 macro def h1_pid=25558
-+ **** h1 0.0 macro def h1_name=/tmp/vtc.25540.59b6ec5d/h1
-+ ** h1 0.0 Wait
-+ ** h1 0.0 Stop HAproxy pid=25558
-+ *** h1 0.0 debug|[ALERT] 157/135318 (25558) : parsing [/tmp/vtc.25540.59b6ec5d/h1/cfg:10] : 'filter' : ''spoe' : missing config file'
-+ *** h1 0.0 debug|[ALERT] 157/135318 (25558) : Error(s) found in configuration file : /tmp/vtc.25540.59b6ec5d/h1/cfg
-+ *** h1 0.0 debug|[ALERT] 157/135318 (25558) : Fatal errors found in configuration.
-+ **** h1 0.0 STDOUT poll 0x10
-+ ** h1 0.0 WAIT4 pid=25558 status=0x0100 (user 0.000000 sys 0.000000)
-+ ** h1 0.0 Found expected ''
-+ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc
-+ ** h1 0.0 Reset and free h1 haproxy -1
-+ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc completed
-+ # top TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc passed (0.004)
-+
-+
-+The following VTC file does almost nothing except running a shell to list
-+the contents of 'tmpdir' directory after having launched a haproxy instance
-+and 's1' HTTP server. This shell also prints the content of 'cfg' 'h1' configuration
-+file.
-+
-+ varnishtest "List the contents of 'tmpdir'"
-+ feature ignore_unknown_macro
-+
-+ server s1 {
-+ } -start
-+
-+ haproxy h1 -conf {
-+ defaults
-+ mode http
-+ timeout connect 5s
-+ timeout server 30s
-+ timeout client 30s
-+
-+ backend be1
-+ server srv1 ${s1_addr}:${s1_port}
-+
-+ frontend http1
-+ use_backend be1
-+ bind "fd@${my_frontend_fd}"
-+ } -start
-+
-+ shell {
-+ echo "${tmpdir} working directory content:"
-+ ls -lR ${tmpdir}
-+ cat ${tmpdir}/h1/cfg
-+ }
-+
-+We give only the output of the shell to illustrate this example:
-+
-+ .
-+ .
-+ .
-+ ** top 0.0 === shell {
-+ **** top 0.0 shell_cmd|exec 2>&1 ;
-+ **** top 0.0 shell_cmd| echo "tmpdir: /tmp/vtc.32092.479d521e"
-+ **** top 0.0 shell_cmd| ls -lR /tmp/vtc.32092.479d521e
-+ **** top 0.0 shell_cmd| cat /tmp/vtc.32092.479d521e/h1/cfg
-+ .
-+ .
-+ .
-+ **** top 0.0 shell_out|/tmp/vtc.3808.448cbfe0 working directory content:
-+ **** top 0.0 shell_out|/tmp/vtc.32092.479d521e:
-+ **** top 0.0 shell_out|total 8
-+ **** top 0.0 shell_out|drwxr-xr-x 2 users 4096 Jun 7 11:09 h1
-+ **** top 0.0 shell_out|-rw-r--r-- 1 me users 84 Jun 7 11:09 INFO
-+ **** top 0.0 shell_out|
-+ **** top 0.0 shell_out|/tmp/vtc.32092.479d521e/h1:
-+ **** top 0.0 shell_out|total 4
-+ **** top 0.0 shell_out|-rw-r----- 1 fred users 339 Jun 7 11:09 cfg
-+ **** top 0.0 shell_out|srw------- 1 fred users 0 Jun 7 11:09 stats.sock
-+ **** top 0.0 shell_out| global
-+ **** top 0.0 shell_out|\tstats socket /tmp/vtc.32092.479d521e/h1/stats.sock level admin mode 600
-+ **** top 0.0 shell_out|
-+ **** top 0.0 shell_out| defaults
-+ **** top 0.0 shell_out| mode http
-+ **** top 0.0 shell_out| timeout connect 5s
-+ **** top 0.0 shell_out| timeout server 30s
-+ **** top 0.0 shell_out| timeout client 30s
-+ **** top 0.0 shell_out|
-+ **** top 0.0 shell_out| backend be1
-+ **** top 0.0 shell_out| server srv1 127.0.0.1:36984
-+ **** top 0.0 shell_out|
-+ **** top 0.0 shell_out| frontend http1
-+ **** top 0.0 shell_out| use_backend be1
-+ **** top 0.0 shell_out| bind "fd@${my_frontend_fd}"
-+ **** top 0.0 shell_status = 0x0000
-+
-+
-+The following example illustrate how to run a basic HTTP transaction between 'c1'
-+client and 's1' server with 'http1' as haproxy frontend. This frontend listen
-+on TCP socket with 'my_frontend_fd' as file descriptor.
-+
-+ # Mandatory line
-+ varnishtest "Basic HAproxy test"
-+
-+ # As some macros for haproxy are used in this file, this line is mandatory.
-+ feature ignore_unknown_macro
-+
-+ server s1 {
-+ rxreq
-+ txresp -body "s1 >>> Hello world!"
-+ } -start
-+
-+ haproxy h1 -conf {
-+ # Configuration file of 'h1' haproxy instance.
-+ defaults
-+ mode http
-+ timeout connect 5s
-+ timeout server 30s
-+ timeout client 30s
-+
-+ backend be1
-+ # declare 'srv1' server to point to 's1' server instance declare above.
-+ server srv1 ${s1_addr}:${s1_port}
-+
-+ frontend http1
-+ use_backend be1
-+ bind "fd@${my_frontend_fd}"
-+ } -start
-+
-+ client c1 -connect ${h1_my_frontend_fd_sock} {
-+ txreq -url "/"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.body == "s1 >>> Hello world!"
-+ } -run
-+
-+
-+It is possible to shorten the previous VTC file haproxy command section as follows:
-+
-+ haproxy h1 -conf {
-+ # Configuration file of 'h1' haproxy instance.
-+ defaults
-+ mode http
-+ timeout connect 5s
-+ timeout server 30s
-+ timeout client 30s
-+ }
-+
-+In this latter example, "backend" and "frontend" sections are automatically
-+generated depending on the declarations of server instances.
-+
-+
-+Another interesting real regression test case is the following: we declare one
-+server 's1', a syslog server 'Slg_1' and a basic haproxy configuration for 'h1'
-+haproxy instance. Here we want to check that the syslog message are correctly
-+formatted thanks to "expect" "syslog" command (see syslog Slg_1 {...} command)
-+below.
-+
-+ varnishtest "Wrong ip/port logging"
-+ feature ignore_unknown_macro
-+
-+ #commit d02286d6c866e5c0a7eb6fbb127fa57f3becaf16
-+ #Author: Willy Tarreau <w@1wt.eu>
-+ #Date: Fri Jun 23 11:23:43 2017 +0200
-+ #
-+ # BUG/MINOR: log: pin the front connection when front ip/ports are logged
-+ #
-+ # Mathias Weiersmueller reported an interesting issue with logs which Lukas
-+ # diagnosed as dating back from commit 9b061e332 (1.5-dev9). When front
-+ # connection information (ip, port) are logged in TCP mode and the log is
-+ # emitted at the end of the connection (eg: because %B or any log tag
-+ # requiring LW_BYTES is set), the log is emitted after the connection is
-+ # closed, so the address and ports cannot be retrieved anymore.
-+ #
-+ # It could be argued that we'd make a special case of these to immediately
-+ # retrieve the source and destination addresses from the connection, but it
-+ # seems cleaner to simply pin the front connection, marking it "tracked" by
-+ # adding the LW_XPRT flag to mention that we'll need some of these elements
-+ # at the last moment. Only LW_FRTIP and LW_CLIP are affected. Note that after
-+ # this change, LW_FRTIP could simply be removed as it's not used anywhere.
-+
-+ # Note that the problem doesn't happen when using %[src] or %[dst] since
-+ # all sample expressions set LW_XPRT.
-+
-+
-+ server s1 {
-+ rxreq
-+ txresp
-+ } -start
-+
-+ syslog Slg_1 -level notice {
-+ recv
-+ recv
-+ recv info
-+ expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_port}.*\"ts\":\"cD\",\"
-+ } -start
-+
-+ haproxy h1 -conf {
-+ global
-+ log ${Slg_1_addr}:${Slg_1_port} local0
-+
-+ defaults
-+ log global
-+ timeout connect 3000
-+ timeout client 5
-+ timeout server 10000
-+
-+ frontend fe1
-+ bind "fd@${fe_1}"
-+ mode tcp
-+ log-format {\"dip\":\"%fi\",\"dport\":\"%fp\",\"c_ip\":\"%ci\",\"c_port\":\"%cp\",\"fe_name\":\"%ft\",\"be_name\":\"%b\",\"s_name\":\"%s\",\"ts\":\"%ts\",\"bytes_read\":\"%B\"}
-+ default_backend be_app
-+
-+ backend be_app
-+ server app1 ${s1_addr}:${s1_port} check
-+ } -start
-+
-+ client c1 -connect ${h1_fe_1_sock} {
-+ txreq -url "/"
-+ delay 0.02
-+ } -run
-+
-+ syslog Slg_1 -wait
-+
-+
-+Here is the output produced by varnishtest with the latter VTC file:
-+
-+ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy
-+ **** top 0.0 extmacro def localhost=127.0.0.1
-+ **** top 0.0 extmacro def bad_backend=127.0.0.1 40386
-+ **** top 0.0 extmacro def bad_ip=192.0.2.255
-+ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy
-+ **** top 0.0 macro def tmpdir=/tmp/vtc.15752.560ca66b
-+ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc starting
-+ ** top 0.0 === varnishtest "HAPEE bug 2788"
-+ * top 0.0 TEST HAPEE bug 2788
-+ ** top 0.0 === feature ignore_unknown_macro
-+ ** top 0.0 === server s1 {
-+ ** s1 0.0 Starting server
-+ **** s1 0.0 macro def s1_addr=127.0.0.1
-+ **** s1 0.0 macro def s1_port=35564
-+ **** s1 0.0 macro def s1_sock=127.0.0.1 35564
-+ * s1 0.0 Listen on 127.0.0.1 35564
-+ ** top 0.0 === syslog Slg_1 -level notice {
-+ ** Slg_1 0.0 Starting syslog server
-+ ** s1 0.0 Started on 127.0.0.1 35564
-+ **** Slg_1 0.0 macro def Slg_1_addr=127.0.0.1
-+ **** Slg_1 0.0 macro def Slg_1_port=33012
-+ **** Slg_1 0.0 macro def Slg_1_sock=127.0.0.1 33012
-+ * Slg_1 0.0 Bound on 127.0.0.1 33012
-+ ** top 0.0 === haproxy h1 -conf {
-+ ** Slg_1 0.0 Started on 127.0.0.1 33012 (level: 5)
-+ ** Slg_1 0.0 === recv
-+ **** h1 0.0 macro def h1_fe_1_sock=::1 51782
-+ **** h1 0.0 macro def h1_fe_1_addr=::1
-+ **** h1 0.0 macro def h1_fe_1_port=51782
-+ **** h1 0.0 setenv(fe_1, 7)
-+ **** h1 0.0 conf| global
-+ **** h1 0.0 conf|\tstats socket /tmp/vtc.15752.560ca66b/h1/stats.sock level admin mode 600
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| global
-+ **** h1 0.0 conf| log 127.0.0.1:33012 local0
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| defaults
-+ **** h1 0.0 conf| log global
-+ **** h1 0.0 conf| timeout connect 3000
-+ **** h1 0.0 conf| timeout client 5
-+ **** h1 0.0 conf| timeout server 10000
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| frontend fe1
-+ **** h1 0.0 conf| bind "fd@${fe_1}"
-+ **** h1 0.0 conf| mode tcp
-+ **** h1 0.0 conf| log-format {\"dip\":\"%fi\",\"dport\":\"%fp\",\"c_ip\":\"%ci\",\"c_port\":\"%cp\",\"fe_name\":\"%ft\",\"be_name\":\"%b\",\"s_name\":\"%s\",\"ts\":\"%ts\",\"bytes_read\":\"%B\"}
-+ **** h1 0.0 conf| default_backend be_app
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| backend be_app
-+ **** h1 0.0 conf| server app1 127.0.0.1:35564 check
-+ ** h1 0.0 haproxy_start
-+ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 0
-+ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -d -f /tmp/vtc.15752.560ca66b/h1/cfg
-+ **** h1 0.0 XXX 9 @277
-+ *** h1 0.0 PID: 15787
-+ **** h1 0.0 macro def h1_pid=15787
-+ **** h1 0.0 macro def h1_name=/tmp/vtc.15752.560ca66b/h1
-+ ** top 0.0 === client c1 -connect ${h1_fe_1_sock} {
-+ ** c1 0.0 Starting client
-+ ** c1 0.0 Waiting for client
-+ *** c1 0.0 Connect to ::1 51782
-+ *** c1 0.0 connected fd 8 from ::1 46962 to ::1 51782
-+ ** c1 0.0 === txreq -url "/"
-+ **** c1 0.0 txreq|GET / HTTP/1.1\r
-+ **** c1 0.0 txreq|Host: 127.0.0.1\r
-+ **** c1 0.0 txreq|\r
-+ ** c1 0.0 === delay 0.02
-+ *** c1 0.0 delaying 0.02 second(s)
-+ *** h1 0.0 debug|Note: setting global.maxconn to 2000.
-+ *** h1 0.0 debug|Available polling systems :
-+ *** h1 0.0 debug| epoll :
-+ *** h1 0.0 debug|pref=300,
-+ *** h1 0.0 debug| test result OK
-+ *** h1 0.0 debug| poll : pref=200, test result OK
-+ *** h1 0.0 debug| select :
-+ *** h1 0.0 debug|pref=150, test result FAILED
-+ *** h1 0.0 debug|Total: 3 (2 usable), will use epoll.
-+ *** h1 0.0 debug|
-+ *** h1 0.0 debug|Available filters :
-+ *** h1 0.0 debug|\t[SPOE] spoe
-+ *** h1 0.0 debug|\t[COMP] compression
-+ *** h1 0.0 debug|\t[TRACE] trace
-+ **** Slg_1 0.0 syslog|<133>Jun 7 14:12:51 haproxy[15787]: Proxy fe1 started.
-+ ** Slg_1 0.0 === recv
-+ **** Slg_1 0.0 syslog|<133>Jun 7 14:12:51 haproxy[15787]: Proxy be_app started.
-+ ** Slg_1 0.0 === recv info
-+ *** h1 0.0 debug|00000000:fe1.accept(0007)=000a from [::1:46962]
-+ *** s1 0.0 accepted fd 6 127.0.0.1 56770
-+ ** s1 0.0 === rxreq
-+ **** s1 0.0 rxhdr|GET / HTTP/1.1\r
-+ **** s1 0.0 rxhdr|Host: 127.0.0.1\r
-+ **** s1 0.0 rxhdr|\r
-+ **** s1 0.0 rxhdrlen = 35
-+ **** s1 0.0 http[ 0] |GET
-+ **** s1 0.0 http[ 1] |/
-+ **** s1 0.0 http[ 2] |HTTP/1.1
-+ **** s1 0.0 http[ 3] |Host: 127.0.0.1
-+ **** s1 0.0 bodylen = 0
-+ ** s1 0.0 === txresp
-+ **** s1 0.0 txresp|HTTP/1.1 200 OK\r
-+ **** s1 0.0 txresp|Content-Length: 0\r
-+ **** s1 0.0 txresp|\r
-+ *** s1 0.0 shutting fd 6
-+ ** s1 0.0 Ending
-+ *** h1 0.0 debug|00000000:be_app.srvcls[000a:000c]
-+ *** h1 0.0 debug|00000000:be_app.clicls[000a:000c]
-+ *** h1 0.0 debug|00000000:be_app.closed[000a:000c]
-+ **** Slg_1 0.0 syslog|<134>Jun 7 14:12:51 haproxy[15787]: {"dip":"","dport":"0","c_ip":"::1","c_port":"46962","fe_name":"fe1","be_name":"be_app","s_name":"app1","ts":"cD","bytes_read":"38"}
-+ ** Slg_1 0.0 === expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_p...
-+ ---- Slg_1 0.0 EXPECT FAILED ~ "\"dip\":\"::1\",\"dport\":\"51782.*\"ts\":\"cD\",\""
-+ *** c1 0.0 closing fd 8
-+ ** c1 0.0 Ending
-+ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/d02286d.vtc
-+ ** h1 0.0 Reset and free h1 haproxy 15787
-+ ** h1 0.0 Wait
-+ ** h1 0.0 Stop HAproxy pid=15787
-+ **** h1 0.0 Kill(2)=0: Success
-+ **** h1 0.0 STDOUT poll 0x10
-+ ** h1 0.1 WAIT4 pid=15787 status=0x0002 (user 0.000000 sys 0.004000)
-+ ** s1 0.1 Waiting for server (4/-1)
-+ ** Slg_1 0.1 Waiting for syslog server (5)
-+ * top 0.1 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc FAILED
-+ # top TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc FAILED (0.131) exit=2
-+
-+This test does not pass without the bug fix of d02286d commit. Indeed the third syslog
-+message received by 'Slg_1' syslog server does not match the regular expression
-+of the "syslog" "expect" command:
-+
-+ expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_port}.*\"ts\":\"cD\",\"
-+
-+(the IP address and port are missing), contrary to what happens with the correct bug fix:
-+
-+ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy
-+ **** top 0.0 extmacro def localhost=127.0.0.1
-+ **** top 0.0 extmacro def bad_backend=127.0.0.1 37284
-+ **** top 0.0 extmacro def bad_ip=192.0.2.255
-+ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy
-+ **** top 0.0 macro def tmpdir=/tmp/vtc.12696.186b28b0
-+ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc starting
-+ ** top 0.0 === varnishtest "HAPEE bug 2788"
-+ * top 0.0 TEST HAPEE bug 2788
-+ ** top 0.0 === feature ignore_unknown_macro
-+ ** top 0.0 === server s1 {
-+ ** s1 0.0 Starting server
-+ **** s1 0.0 macro def s1_addr=127.0.0.1
-+ **** s1 0.0 macro def s1_port=53384
-+ **** s1 0.0 macro def s1_sock=127.0.0.1 53384
-+ * s1 0.0 Listen on 127.0.0.1 53384
-+ ** top 0.0 === syslog Slg_1 -level notice {
-+ ** Slg_1 0.0 Starting syslog server
-+ **** Slg_1 0.0 macro def Slg_1_addr=127.0.0.1
-+ ** s1 0.0 Started on 127.0.0.1 53384
-+ **** Slg_1 0.0 macro def Slg_1_port=36195
-+ **** Slg_1 0.0 macro def Slg_1_sock=127.0.0.1 36195
-+ * Slg_1 0.0 Bound on 127.0.0.1 36195
-+ ** top 0.0 === haproxy h1 -conf {
-+ ** Slg_1 0.0 Started on 127.0.0.1 36195 (level: 5)
-+ ** Slg_1 0.0 === recv
-+ **** h1 0.0 macro def h1_fe_1_sock=::1 39264
-+ **** h1 0.0 macro def h1_fe_1_addr=::1
-+ **** h1 0.0 macro def h1_fe_1_port=39264
-+ **** h1 0.0 setenv(fe_1, 7)
-+ **** h1 0.0 conf| global
-+ **** h1 0.0 conf|\tstats socket /tmp/vtc.12696.186b28b0/h1/stats.sock level admin mode 600
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| global
-+ **** h1 0.0 conf| log 127.0.0.1:36195 local0
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| defaults
-+ **** h1 0.0 conf| log global
-+ **** h1 0.0 conf| timeout connect 3000
-+ **** h1 0.0 conf| timeout client 5
-+ **** h1 0.0 conf| timeout server 10000
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| frontend fe1
-+ **** h1 0.0 conf| bind "fd@${fe_1}"
-+ **** h1 0.0 conf| mode tcp
-+ **** h1 0.0 conf| log-format {\"dip\":\"%fi\",\"dport\":\"%fp\",\"c_ip\":\"%ci\",\"c_port\":\"%cp\",\"fe_name\":\"%ft\",\"be_name\":\"%b\",\"s_name\":\"%s\",\"ts\":\"%ts\",\"bytes_read\":\"%B\"}
-+ **** h1 0.0 conf| default_backend be_app
-+ **** h1 0.0 conf|
-+ **** h1 0.0 conf| backend be_app
-+ **** h1 0.0 conf| server app1 127.0.0.1:53384 check
-+ ** h1 0.0 haproxy_start
-+ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 0
-+ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -d -f /tmp/vtc.12696.186b28b0/h1/cfg
-+ **** h1 0.0 XXX 9 @277
-+ *** h1 0.0 PID: 12728
-+ **** h1 0.0 macro def h1_pid=12728
-+ **** h1 0.0 macro def h1_name=/tmp/vtc.12696.186b28b0/h1
-+ ** top 0.0 === client c1 -connect ${h1_fe_1_sock} {
-+ ** c1 0.0 Starting client
-+ ** c1 0.0 Waiting for client
-+ *** c1 0.0 Connect to ::1 39264
-+ *** c1 0.0 connected fd 8 from ::1 41245 to ::1 39264
-+ ** c1 0.0 === txreq -url "/"
-+ **** c1 0.0 txreq|GET / HTTP/1.1\r
-+ **** c1 0.0 txreq|Host: 127.0.0.1\r
-+ **** c1 0.0 txreq|\r
-+ ** c1 0.0 === delay 0.02
-+ *** c1 0.0 delaying 0.02 second(s)
-+ *** h1 0.0 debug|Note: setting global.maxconn to 2000.
-+ *** h1 0.0 debug|Available polling systems :
-+ *** h1 0.0 debug| epoll : pref=300,
-+ *** h1 0.0 debug| test result OK
-+ *** h1 0.0 debug| poll : pref=200, test result OK
-+ *** h1 0.0 debug| select : pref=150, test result FAILED
-+ *** h1 0.0 debug|Total: 3 (2 usable), will use epoll.
-+ *** h1 0.0 debug|
-+ *** h1 0.0 debug|Available filters :
-+ *** h1 0.0 debug|\t[SPOE] spoe
-+ *** h1 0.0 debug|\t[COMP] compression
-+ *** h1 0.0 debug|\t[TRACE] trace
-+ *** h1 0.0 debug|Using epoll() as the polling mechanism.
-+ **** Slg_1 0.0 syslog|<133>Jun 7 14:10:18 haproxy[12728]: Proxy fe1 started.
-+ ** Slg_1 0.0 === recv
-+ **** Slg_1 0.0 syslog|<133>Jun 7 14:10:18 haproxy[12728]: Proxy be_app started.
-+ ** Slg_1 0.0 === recv info
-+ *** h1 0.0 debug|00000000:fe1.accept(0007)=000c from [::1:41245] ALPN=<none>
-+ *** s1 0.0 accepted fd 6 127.0.0.1 49946
-+ ** s1 0.0 === rxreq
-+ **** s1 0.0 rxhdr|GET / HTTP/1.1\r
-+ **** s1 0.0 rxhdr|Host: 127.0.0.1\r
-+ **** s1 0.0 rxhdr|\r
-+ **** s1 0.0 rxhdrlen = 35
-+ **** s1 0.0 http[ 0] |GET
-+ **** s1 0.0 http[ 1] |/
-+ **** s1 0.0 http[ 2] |HTTP/1.1
-+ **** s1 0.0 http[ 3] |Host: 127.0.0.1
-+ **** s1 0.0 bodylen = 0
-+ ** s1 0.0 === txresp
-+ **** s1 0.0 txresp|HTTP/1.1 200 OK\r
-+ **** s1 0.0 txresp|Content-Length: 0\r
-+ **** s1 0.0 txresp|\r
-+ *** s1 0.0 shutting fd 6
-+ ** s1 0.0 Ending
-+ *** h1 0.0 debug|00000000:be_app.srvcls[000c:adfd]
-+ *** h1 0.0 debug|00000000:be_app.clicls[000c:adfd]
-+ *** h1 0.0 debug|00000000:be_app.closed[000c:adfd]
-+ **** Slg_1 0.0 syslog|<134>Jun 7 14:10:18 haproxy[12728]: {"dip":"::1","dport":"39264","c_ip":"::1","c_port":"41245","fe_name":"fe1","be_name":"be_app","s_name":"app1","ts":"cD","bytes_read":"38"}
-+ ** Slg_1 0.0 === expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_p...
-+ **** Slg_1 0.0 EXPECT MATCH ~ "\"dip\":\"::1\",\"dport\":\"39264.*\"ts\":\"cD\",\""
-+ *** Slg_1 0.0 shutting fd 5
-+ ** Slg_1 0.0 Ending
-+ *** c1 0.0 closing fd 8
-+ ** c1 0.0 Ending
-+ ** top 0.0 === syslog Slg_1 -wait
-+ ** Slg_1 0.0 Waiting for syslog server (-1)
-+ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/d02286d.vtc
-+ ** h1 0.0 Reset and free h1 haproxy 12728
-+ ** h1 0.0 Wait
-+ ** h1 0.0 Stop HAproxy pid=12728
-+ **** h1 0.0 Kill(2)=0: Success
-+ **** h1 0.0 STDOUT poll 0x10
-+ ** h1 0.1 WAIT4 pid=12728 status=0x0002 (user 0.000000 sys 0.004000)
-+ ** s1 0.1 Waiting for server (4/-1)
-+ * top 0.1 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc completed
-+ # top TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc passed (0.128)
-+
-+In this latter execution the third syslog message is correct:
-+
-+ **** Slg_1 0.0 syslog|<134>Jun 7 14:10:18 haproxy[12728]: {"dip":"::1","dport":"39264","c_ip":"::1","c_port":"41245","fe_name":"fe1","be_name":"be_app","s_name":"app1","ts":"cD","bytes_read":"38"}
+++ /dev/null
-commit b3dae591a4fb47922d4235cf05ac66bcce443cf4
-Author: Ilya Shipitsin <chipitsine@gmail.com>
-Date: Sat May 25 03:38:14 2019 +0500
-
- BUG/MINOR: ssl_sock: Fix memory leak when disabling compression
-
- according to manpage:
-
- sk_TYPE_zero() sets the number of elements in sk to zero. It
- does not free sk so after this call sk is still valid.
-
- so we need to free all elements
-
- [wt: seems like it has been there forever and should be backported
- to all stable branches]
-
- (cherry picked from commit e242f3dfb8ae2f27de9d10d90a783df05d5c849b)
- [wt: adjusted context due to libressl detection]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit 273c61dfb45d968eb8b677616130cda6586977f0)
- [wt: minor adjustments due to version detection and local variables]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
-
-diff --git a/src/ssl_sock.c b/src/ssl_sock.c
-index fbb7cf2b..3ab63342 100644
---- a/src/ssl_sock.c
-+++ b/src/ssl_sock.c
-@@ -8959,11 +8959,10 @@ static void ssl_sock_capture_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *
- __attribute__((constructor))
- static void __ssl_sock_init(void)
- {
-+ STACK_OF(SSL_COMP)* cm;
- char *ptr;
- int i;
-
-- STACK_OF(SSL_COMP)* cm;
--
- if (global_ssl.listen_default_ciphers)
- global_ssl.listen_default_ciphers = strdup(global_ssl.listen_default_ciphers);
- if (global_ssl.connect_default_ciphers)
-@@ -8978,7 +8977,11 @@ static void __ssl_sock_init(void)
- xprt_register(XPRT_SSL, &ssl_sock);
- SSL_library_init();
- cm = SSL_COMP_get_compression_methods();
-- sk_SSL_COMP_zero(cm);
-+ i = sk_SSL_COMP_num(cm);
-+ while (i--) {
-+ (void) sk_SSL_COMP_pop(cm);
-+ }
-+
- #ifdef USE_THREAD
- ssl_locking_init();
- #endif
+++ /dev/null
-commit e834ca5c6914c71a86138362423b9d6e7ce15a78
-Author: Ilya Shipitsin <chipitsine@gmail.com>
-Date: Sat May 25 19:30:50 2019 +0500
-
- BUILD: ssl: fix latest LibreSSL reg-test error
-
- starting with OpenSSL 1.0.0 recommended way to disable compression is
- using SSL_OP_NO_COMPRESSION when creating context.
-
- manipulations with SSL_COMP_get_compression_methods, sk_SSL_COMP_num
- are only required for OpenSSL < 1.0.0
-
- (cherry picked from commit 0590f44254da9203a3c9d239836f4703aa6d543b)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit be086d6dc7029aec9349e54ab5cccc499892bd61)
- [wt: context adjustments]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
-
-diff --git a/src/ssl_sock.c b/src/ssl_sock.c
-index 3ab63342..3436459f 100644
---- a/src/ssl_sock.c
-+++ b/src/ssl_sock.c
-@@ -8959,7 +8959,9 @@ static void ssl_sock_capture_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *
- __attribute__((constructor))
- static void __ssl_sock_init(void)
- {
-+#if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION))
- STACK_OF(SSL_COMP)* cm;
-+#endif
- char *ptr;
- int i;
-
-@@ -8976,11 +8978,13 @@ static void __ssl_sock_init(void)
-
- xprt_register(XPRT_SSL, &ssl_sock);
- SSL_library_init();
-+#if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION))
- cm = SSL_COMP_get_compression_methods();
- i = sk_SSL_COMP_num(cm);
- while (i--) {
- (void) sk_SSL_COMP_pop(cm);
- }
-+#endif
-
- #ifdef USE_THREAD
- ssl_locking_init();
+++ /dev/null
-commit 5d60902ec7883bb05927c648638a009eb930acc7
-Author: Willy Tarreau <w@1wt.eu>
-Date: Mon May 27 10:17:05 2019 +0200
-
- BUG/MAJOR: lb/threads: make sure the avoided server is not full on second pass
-
- In fwrr_get_next_server(), we optionally pass a server to avoid. It
- usually points to the current server during a redispatch operation. If
- this server is usable, an "avoided" pointer is set and we continue to
- look for another server. If in the end no other server is found, then
- we fall back to this avoided one, which is still better than nothing.
-
- The problem that may arise with threads is that in the mean time, this
- avoided server might have received extra connections and might not be
- usable anymore. This causes it to be queued a second time in the "full"
- list and the loop to search for a server again, ending up on this one
- again and so on.
-
- This patch makes sure that we break out of the loop when we have to
- pick the avoided server. It's probably what the code intended to do
- as the current break statement causes fwrr_update_position() and
- fwrr_dequeue_srv() to be called again on the avoided server.
-
- It must be backported to 1.9 and 1.8, and seems appropriate for older
- versions though it's unclear what the impact of this bug might be
- there since the race doesn't exist and we're left with the double
- update of the server's position.
-
- (cherry picked from commit b6195ef2a6b0cb3f68bc34735313daa640ab3e92)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit 7df15f275af90110e6ab4ec75065cbfabdf764ec)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
-
-diff --git a/src/lb_fwrr.c b/src/lb_fwrr.c
-index cba7db5f..33181b46 100644
---- a/src/lb_fwrr.c
-+++ b/src/lb_fwrr.c
-@@ -504,7 +504,7 @@ struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid)
- if (switched) {
- if (avoided) {
- srv = avoided;
-- break;
-+ goto take_this_one;
- }
- goto requeue_servers;
- }
-@@ -534,6 +534,7 @@ struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid)
- full = srv;
- }
-
-+ take_this_one:
- /* OK, we got the best server, let's update it */
- fwrr_queue_srv(srv);
-
+++ /dev/null
-commit 339e69400f87c34e28c67eaab6e503dc41b29d48
-Author: Willy Tarreau <w@1wt.eu>
-Date: Tue May 28 08:26:17 2019 +0200
-
- BUG/MEDIUM: http: fix "http-request reject" when not final
-
- When "http-request reject" was introduced in 1.8 with commit 53275e8b0
- ("MINOR: http: implement the "http-request reject" rule"), it was already
- broken. The code mentions "it always returns ACT_RET_STOP" and obviously
- a gross copy-paste made it ACT_RET_CONT. If the rule is the last one it
- properly blocks, but if not the last one it gets ignored, as can be seen
- with this simple configuration :
-
- frontend f1
- bind :8011
- mode http
- http-request reject
- http-request redirect location /
-
- This trivial fix must be backported to 1.9 and 1.8. It is tracked by
- github issue #107.
-
- (cherry picked from commit 11c90fbd92cfaa5695e328481402d62d536456ef)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit f6d5f2b27634cf3f8591016985b9fb81a1caf01c)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
- [Cf: The fix was applied in the file src/proto_http.c because, in 1.8, the file
- src/http_act.c does not exist.]
-
-diff --git a/src/proto_http.c b/src/proto_http.c
-index 32aeef2d..e5792f8c 100644
---- a/src/proto_http.c
-+++ b/src/proto_http.c
-@@ -12157,7 +12157,7 @@ enum act_return http_action_reject(struct act_rule *rule, struct proxy *px,
- if (!(s->flags & SF_FINST_MASK))
- s->flags |= SF_FINST_R;
-
-- return ACT_RET_CONT;
-+ return ACT_RET_STOP;
- }
-
- /* parse the "reject" action:
+++ /dev/null
-commit ee60daed3071426242fcacbb1cd9603a825b359e
-Author: Willy Tarreau <w@1wt.eu>
-Date: Sun Jun 2 11:11:29 2019 +0200
-
- BUG/MINOR: deinit/threads: make hard-stop-after perform a clean exit
-
- As reported in GH issue #99, when hard-stop-after triggers and threads
- are in use, the chance that any thread releases the resources in use by
- the other ones is non-null. Thus no thread should be allowed to deinit()
- nor exit by itself.
-
- Here we take a different approach. We simply use a 3rd possible value
- for the "killed" variable so that all threads know they must break out
- of the run-poll-loop and immediately stop.
-
- This patch was tested by commenting the stream_shutdown() calls in
- hard_stop() to increase the chances to see a stream use released
- resources. With this fix applied, it never crashes anymore.
-
- This fix should be backported to 1.9 and 1.8.
-
- (cherry picked from commit 7067b3a92efc9c9a7c3239245fdc96ea7310f46a)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit daf91d3a5c8d2b47878580a0e0bde654d92ad42a)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/include/types/global.h b/include/types/global.h
-index bd7761cd..d3721d03 100644
---- a/include/types/global.h
-+++ b/include/types/global.h
-@@ -213,7 +213,7 @@ extern const int zero;
- extern const int one;
- extern const struct linger nolinger;
- extern int stopping; /* non zero means stopping in progress */
--extern int killed; /* non zero means a hard-stop is triggered */
-+extern int killed; /* >0 means a hard-stop is triggered, >1 means hard-stop immediately */
- extern char hostname[MAX_HOSTNAME_LEN];
- extern char localpeer[MAX_HOSTNAME_LEN];
- extern struct list global_listener_queue; /* list of the temporarily limited listeners */
-diff --git a/src/haproxy.c b/src/haproxy.c
-index 105cde6f..6ea17a0c 100644
---- a/src/haproxy.c
-+++ b/src/haproxy.c
-@@ -2431,6 +2431,10 @@ static void run_poll_loop()
- if (tid == 0 && jobs == 0)
- THREAD_WANT_SYNC();
-
-+ /* also stop if we failed to cleanly stop all tasks */
-+ if (killed > 1)
-+ break;
-+
- /* expire immediately if events are pending */
- exp = now_ms;
- if (fd_cache_mask & tid_bit)
-diff --git a/src/proxy.c b/src/proxy.c
-index cff6c0aa..ef491aed 100644
---- a/src/proxy.c
-+++ b/src/proxy.c
-@@ -942,9 +942,9 @@ struct task *hard_stop(struct task *t)
- if (killed) {
- ha_warning("Some tasks resisted to hard-stop, exiting now.\n");
- send_log(NULL, LOG_WARNING, "Some tasks resisted to hard-stop, exiting now.\n");
-- /* Do some cleanup and explicitely quit */
-- deinit();
-- exit(0);
-+ killed = 2;
-+ t->expire = TICK_ETERNITY;
-+ return t;
- }
-
- ha_warning("soft-stop running for too long, performing a hard-stop.\n");
+++ /dev/null
-commit 30e228120ebc1caad1086d0d90383f472f710375
-Author: Willy Tarreau <w@1wt.eu>
-Date: Mon Jun 3 08:17:30 2019 +0200
-
- BUG/MEDIUM: connection: fix multiple handshake polling issues
-
- Connection handshakes were rarely stacked on top of each other, but the
- recent experiments consisting in sending PROXY over SOCKS4 revealed a
- number of issues in these lower layers. First, each handler waiting for
- data MUST subscribe to recv events with __conn_sock_want_recv() and MUST
- unsubscribe from send events using __conn_sock_stop_send() to avoid any
- wake-up loop in case a previous sender has set this. Second, each handler
- waiting for sending MUST subscribe to send events with __conn_sock_want_send()
- and MUST unsubscribe from recv events using __conn_sock_stop_recv() to
- avoid any wake-up loop in case some data are available on the connection.
-
- Till now this was done at various random places, and in particular the
- cases where the FD was not ready for recv forgot to re-enable reading.
-
- Second, while senders can happily use conn_sock_send() which automatically
- handles EINTR, loops, and marks the FD as not ready with fd_cant_send(),
- there is no equivalent for recv so receivers facing EAGAIN MUST call
- fd_cant_send() to enable polling. It could be argued that implementing
- an equivalent conn_sock_recv() function could be useful and more
- long-term proof than the current situation.
-
- Third, both types of handlers MUST unsubscribe from their respective
- events once they managed to do their job, and none may even play with
- __conn_xprt_*(). Here again this was lacking, and one surprizing call
- to __conn_xprt_stop_recv() was present in the proxy protocol parser
- for TCP6 messages!
-
- Thanks to Alexander Liu for his help on this issue.
-
- This patch must be backported to 1.9 and possibly some older versions,
- though the SOCKS parts should be dropped.
-
- (cherry picked from commit 6499b9d996ea8f57749021f56ed635c4688a727e)
- [wt: dropped SOCKS4]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit a34d37966ed87ffd9924e2b11f8003dc773e1853)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/connection.c b/src/connection.c
-index f57ef60a..e00c2f81 100644
---- a/src/connection.c
-+++ b/src/connection.c
-@@ -404,7 +404,7 @@ int conn_recv_proxy(struct connection *conn, int flag)
- goto fail;
-
- if (!fd_recv_ready(conn->handle.fd))
-- return 0;
-+ goto not_ready;
-
- do {
- trash.len = recv(conn->handle.fd, trash.str, trash.size, MSG_PEEK);
-@@ -413,7 +413,7 @@ int conn_recv_proxy(struct connection *conn, int flag)
- continue;
- if (errno == EAGAIN) {
- fd_cant_recv(conn->handle.fd);
-- return 0;
-+ goto not_ready;
- }
- goto recv_abort;
- }
-@@ -653,8 +653,14 @@ int conn_recv_proxy(struct connection *conn, int flag)
-
- conn->flags &= ~flag;
- conn->flags |= CO_FL_RCVD_PROXY;
-+ __conn_sock_stop_recv(conn);
- return 1;
-
-+ not_ready:
-+ __conn_sock_want_recv(conn);
-+ __conn_sock_stop_send(conn);
-+ return 0;
-+
- missing:
- /* Missing data. Since we're using MSG_PEEK, we can only poll again if
- * we have not read anything. Otherwise we need to fail because we won't
-@@ -709,7 +715,7 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
- goto fail;
-
- if (!fd_recv_ready(conn->handle.fd))
-- return 0;
-+ goto not_ready;
-
- do {
- trash.len = recv(conn->handle.fd, trash.str, trash.size, MSG_PEEK);
-@@ -718,7 +724,7 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
- continue;
- if (errno == EAGAIN) {
- fd_cant_recv(conn->handle.fd);
-- return 0;
-+ goto not_ready;
- }
- goto recv_abort;
- }
-@@ -849,8 +855,14 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
- } while (0);
-
- conn->flags &= ~flag;
-+ __conn_sock_stop_recv(conn);
- return 1;
-
-+ not_ready:
-+ __conn_sock_want_recv(conn);
-+ __conn_sock_stop_send(conn);
-+ return 0;
-+
- missing:
- /* Missing data. Since we're using MSG_PEEK, we can only poll again if
- * we have not read anything. Otherwise we need to fail because we won't
-diff --git a/src/stream_interface.c b/src/stream_interface.c
-index 47a100d7..8e4df70a 100644
---- a/src/stream_interface.c
-+++ b/src/stream_interface.c
-@@ -400,6 +400,7 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag)
- if (conn->flags & CO_FL_WAIT_L4_CONN)
- conn->flags &= ~CO_FL_WAIT_L4_CONN;
- conn->flags &= ~flag;
-+ __conn_sock_stop_send(conn);
- return 1;
-
- out_error:
-@@ -409,6 +410,7 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag)
-
- out_wait:
- __conn_sock_stop_recv(conn);
-+ __conn_sock_want_send(conn);
- return 0;
- }
-
+++ /dev/null
-commit 47133bd99225554519c1d32293e0e5c3db83db30
-Author: Willy Tarreau <w@1wt.eu>
-Date: Tue Jun 4 16:27:36 2019 +0200
-
- BUG/MEDIUM: vars: make sure the scope is always valid when accessing vars
-
- Patrick Hemmer reported that a simple tcp rule involving a variable like
- this is enough to crash haproxy :
-
- frontend foo
- bind :8001
- tcp-request session set-var(txn.foo) src
-
- The tests on the variables scopes is not strict enough, it needs to always
- verify if the stream is valid when accessing a req/res/txn variable. This
- patch does this by adding a new get_vars() function which does the job
- instead of open-coding all the lookups everywhere.
-
- It must be backported to all versions supporting set-var and
- "tcp-request session" so at least 1.9 and 1.8.
-
- (cherry picked from commit f37b140b06b9963dea8adaf5e13b5b57cd219c74)
- [wt: s/_HA_/HA_/]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit 5dcf8515592602ed0d962e365cbb74a3646727c1)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/vars.c b/src/vars.c
-index 566ead6e..c86f612f 100644
---- a/src/vars.c
-+++ b/src/vars.c
-@@ -34,6 +34,25 @@ static unsigned int var_reqres_limit = 0;
-
- __decl_hathreads(HA_RWLOCK_T var_names_rwlock);
-
-+/* returns the struct vars pointer for a session, stream and scope, or NULL if
-+ * it does not exist.
-+ */
-+static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope)
-+{
-+ switch (scope) {
-+ case SCOPE_PROC:
-+ return &global.vars;
-+ case SCOPE_SESS:
-+ return &sess->vars;
-+ case SCOPE_TXN:
-+ return strm ? &strm->vars_txn : NULL;
-+ case SCOPE_REQ:
-+ case SCOPE_RES:
-+ default:
-+ return strm ? &strm->vars_reqres : NULL;
-+ }
-+}
-+
- /* This function adds or remove memory size from the accounting. The inner
- * pointers may be null when setting the outer ones only.
- */
-@@ -42,10 +61,12 @@ static void var_accounting_diff(struct vars *vars, struct session *sess, struct
- switch (vars->scope) {
- case SCOPE_REQ:
- case SCOPE_RES:
-- HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
-+ if (strm)
-+ HA_ATOMIC_ADD(&strm->vars_reqres.size, size);
- /* fall through */
- case SCOPE_TXN:
-- HA_ATOMIC_ADD(&strm->vars_txn.size, size);
-+ if (strm)
-+ HA_ATOMIC_ADD(&strm->vars_txn.size, size);
- /* fall through */
- case SCOPE_SESS:
- HA_ATOMIC_ADD(&sess->vars.size, size);
-@@ -68,11 +89,11 @@ static int var_accounting_add(struct vars *vars, struct session *sess, struct st
- switch (vars->scope) {
- case SCOPE_REQ:
- case SCOPE_RES:
-- if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_limit)
-+ if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit)
- return 0;
- /* fall through */
- case SCOPE_TXN:
-- if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit)
-+ if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
- return 0;
- /* fall through */
- case SCOPE_SESS:
-@@ -285,27 +306,8 @@ static int smp_fetch_var(const struct arg *args, struct sample *smp, const char
- struct vars *vars;
-
- /* Check the availibity of the variable. */
-- switch (var_desc->scope) {
-- case SCOPE_PROC:
-- vars = &global.vars;
-- break;
-- case SCOPE_SESS:
-- vars = &smp->sess->vars;
-- break;
-- case SCOPE_TXN:
-- if (!smp->strm)
-- return 0;
-- vars = &smp->strm->vars_txn;
-- break;
-- case SCOPE_REQ:
-- case SCOPE_RES:
-- default:
-- if (!smp->strm)
-- return 0;
-- vars = &smp->strm->vars_reqres;
-- break;
-- }
-- if (vars->scope != var_desc->scope)
-+ vars = get_vars(smp->sess, smp->strm, var_desc->scope);
-+ if (!vars || vars->scope != var_desc->scope)
- return 0;
-
- HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock);
-@@ -423,15 +425,8 @@ static inline int sample_store_stream(const char *name, enum vars_scope scope, s
- struct vars *vars;
- int ret;
-
-- switch (scope) {
-- case SCOPE_PROC: vars = &global.vars; break;
-- case SCOPE_SESS: vars = &smp->sess->vars; break;
-- case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
-- case SCOPE_REQ:
-- case SCOPE_RES:
-- default: vars = &smp->strm->vars_reqres; break;
-- }
-- if (vars->scope != scope)
-+ vars = get_vars(smp->sess, smp->strm, scope);
-+ if (!vars || vars->scope != scope)
- return 0;
-
- HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock);
-@@ -447,15 +442,8 @@ static inline int sample_clear_stream(const char *name, enum vars_scope scope, s
- struct var *var;
- unsigned int size = 0;
-
-- switch (scope) {
-- case SCOPE_PROC: vars = &global.vars; break;
-- case SCOPE_SESS: vars = &smp->sess->vars; break;
-- case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
-- case SCOPE_REQ:
-- case SCOPE_RES:
-- default: vars = &smp->strm->vars_reqres; break;
-- }
-- if (vars->scope != scope)
-+ vars = get_vars(smp->sess, smp->strm, scope);
-+ if (!vars || vars->scope != scope)
- return 0;
-
- /* Look for existing variable name. */
-@@ -586,17 +574,8 @@ int vars_get_by_name(const char *name, size_t len, struct sample *smp)
- return 0;
-
- /* Select "vars" pool according with the scope. */
-- switch (scope) {
-- case SCOPE_PROC: vars = &global.vars; break;
-- case SCOPE_SESS: vars = &smp->sess->vars; break;
-- case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
-- case SCOPE_REQ:
-- case SCOPE_RES:
-- default: vars = &smp->strm->vars_reqres; break;
-- }
--
-- /* Check if the scope is avalaible a this point of processing. */
-- if (vars->scope != scope)
-+ vars = get_vars(smp->sess, smp->strm, scope);
-+ if (!vars || vars->scope != scope)
- return 0;
-
- /* Get the variable entry. */
-@@ -620,17 +599,10 @@ int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp)
- struct var *var;
-
- /* Select "vars" pool according with the scope. */
-- switch (var_desc->scope) {
-- case SCOPE_PROC: vars = &global.vars; break;
-- case SCOPE_SESS: vars = &smp->sess->vars; break;
-- case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
-- case SCOPE_REQ:
-- case SCOPE_RES:
-- default: vars = &smp->strm->vars_reqres; break;
-- }
-+ vars = get_vars(smp->sess, smp->strm, var_desc->scope);
-
-- /* Check if the scope is avalaible a this point of processing. */
-- if (vars->scope != var_desc->scope)
-+ /* Check if the scope is available a this point of processing. */
-+ if (!vars || vars->scope != var_desc->scope)
- return 0;
-
- /* Get the variable entry. */
+++ /dev/null
-commit a41ac2d710711f3ab91d92415278a73c358aedca
-Author: Willy Tarreau <w@1wt.eu>
-Date: Tue Jun 4 16:43:29 2019 +0200
-
- BUG/MEDIUM: vars: make the tcp/http unset-var() action support conditions
-
- Patrick Hemmer reported that http-request unset-var(foo) if ... fails to
- parse. The reason is that it reuses the same parser as "set-var(foo)" which
- makes a special case of the arguments, supposed to be a sample expression
- for set-var, but which must not exist for unset-var. Unfortunately the
- parser finds "if" or "unless" and believes it's an expression. Let's simply
- drop the test so that the outer rule parser deals with potential extraneous
- keywords.
-
- This should be backported to all versions supporting unset-var().
-
- (cherry picked from commit 4b7531f48b5aa66d11fcee2836c201644bfb6a71)
- Signed-off-by: Willy Tarreau <w@1wt.eu>
- (cherry picked from commit a47e745276662db361637914b8558984f091306b)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/vars.c b/src/vars.c
-index c86f612f..d69fb838 100644
---- a/src/vars.c
-+++ b/src/vars.c
-@@ -684,6 +684,7 @@ static int conv_check_var(struct arg *args, struct sample_conv *conv,
- * the format:
- *
- * set-var(<variable-name>) <expression>
-+ * unset-var(<variable-name>)
- *
- * It returns ACT_RET_PRS_ERR if fails and <err> is filled with an error
- * message. Otherwise, it returns ACT_RET_PRS_OK and the variable <expr>
-@@ -727,10 +728,6 @@ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy
- /* There is no fetch method when variable is unset. Just set the right
- * action and return. */
- if (!set_var) {
-- if (*args[*arg]) {
-- memprintf(err, "fetch method not supported");
-- return ACT_RET_PRS_ERR;
-- }
- rule->action = ACT_CUSTOM;
- rule->action_ptr = action_clear;
- return ACT_RET_PRS_OK;
+++ /dev/null
-commit e7c30a33646f4ec73041ea57bd9fdcdc3e4a80ab
-Author: Willy Tarreau <w@1wt.eu>
-Date: Fri Jun 7 08:20:46 2019 +0200
-
- BUG/MEDIUM: mux-h2: make sure the connection timeout is always set
-
- There seems to be a tricky case in the H2 mux related to stream flow
- control versus buffer a full situation : is a large response cannot
- be entirely sent to the client due to the stream window being too
- small, the stream is paused with the SFCTL flag. Then the upper
- layer stream might get bored and expire this stream. It will then
- shut it down first. But the shutdown operation might fail if the
- mux buffer is full, resulting in the h2s being subscribed to the
- deferred_shut event with the stream *not* added to the send_list
- since it's blocked in SFCTL. In the mean time the upper layer completely
- closes, calling h2_detach(). There we have a send_wait (the pending
- shutw), the stream is marked with SFCTL so we orphan it.
-
- Then if the client finally reads all the data that were clogging the
- buffer, the send_list is run again, but our stream is not there. From
- this point, the connection's stream list is not empty, the mux buffer
- is empty, so the connection's timeout is not set. If the client
- disappears without updating the stream's window, nothing will expire
- the connection.
-
- This patch makes sure we always keep the connection timeout updated.
- There might be finer solutions, such as checking that there are still
- living streams in the connection (i.e. streams not blocked in SFCTL
- state), though this is not necessarily trivial nor useful, since the
- client timeout is the same for the upper level stream and the connection
- anyway.
-
- This patch needs to be backported to 1.9 and 1.8 after some observation.
-
- (cherry picked from commit 7348119fb22bf761c33e06e8a092bd006660cc81)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit e76090f78b6b8c519abf20061bfc5a4423816ea5)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/src/mux_h2.c b/src/mux_h2.c
-index b2f3096e..985b9742 100644
---- a/src/mux_h2.c
-+++ b/src/mux_h2.c
-@@ -2406,12 +2406,8 @@ static int h2_wake(struct connection *conn)
- }
-
- if (h2c->task) {
-- if (eb_is_empty(&h2c->streams_by_id) || h2c->mbuf->o) {
-- h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
-- task_queue(h2c->task);
-- }
-- else
-- h2c->task->expire = TICK_ETERNITY;
-+ h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
-+ task_queue(h2c->task);
- }
- return 0;
- }
-@@ -2587,12 +2583,8 @@ static void h2_detach(struct conn_stream *cs)
- h2_release(h2c->conn);
- }
- else if (h2c->task) {
-- if (eb_is_empty(&h2c->streams_by_id) || h2c->mbuf->o) {
-- h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
-- task_queue(h2c->task);
-- }
-- else
-- h2c->task->expire = TICK_ETERNITY;
-+ h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
-+ task_queue(h2c->task);
- }
- }
-
+++ /dev/null
-commit 8a74cad9b7fe8b9e1f5b140d90360ece838a878e
-Author: Willy Tarreau <w@1wt.eu>
-Date: Tue Jun 11 16:01:56 2019 +0200
-
- BUG/MINOR: http-rules: mention "deny_status" for "deny" in the error message
-
- The error message indicating an unknown keyword on an http-request rule
- doesn't mention the "deny_status" option which comes with the "deny" rule,
- this is particularly confusing.
-
- This can be backported to all versions supporting this option.
-
- (cherry picked from commit 5abdc760c99a0011607f2cc97e199ef6ce0e8486)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 4e66beaf2a32bd835db9de61a60318648258f649)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
- [Cf: The fix was applied on src/proto_http.c because, in 1.8, the file
- src/http_rules.c does not exist.]
-
-diff --git a/src/proto_http.c b/src/proto_http.c
-index e5792f8c..689e0e31 100644
---- a/src/proto_http.c
-+++ b/src/proto_http.c
-@@ -8830,7 +8830,8 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
- rule->cond = cond;
- }
- else if (*args[cur_arg]) {
-- ha_alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
-+ ha_alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth',"
-+ " 'deny_status' for 'deny', or"
- " either 'if' or 'unless' followed by a condition but found '%s'.\n",
- file, linenum, args[0], args[cur_arg]);
- goto out_err;
+++ /dev/null
-commit 8f2772f5c603168ad3f79adc9e17569f510274ca
-Author: Kazuo Yagi <kazuo.yagi@gmail.com>
-Date: Thu Jun 13 17:14:57 2019 +0900
-
- MINOR: doc: Remove -Ds option in man page
-
- Remove -Ds option in man page.
-
- Should be backported in every version since 1.8.
-
- (cherry picked from commit 971c3943be1283e9d377d68f95ea467304b3a8da)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit a5e78ea5150f31190e4c1cd38fa7c1cadbf1ae8a)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/doc/haproxy.1 b/doc/haproxy.1
-index 91f58a3b..cfed2cf7 100644
---- a/doc/haproxy.1
-+++ b/doc/haproxy.1
-@@ -77,10 +77,6 @@ starting up.
- \fB\-D\fP
- Start in daemon mode.
-
--.TP
--\fB\-Ds\fP
--Start in systemd daemon mode, keeping a process in foreground.
--
- .TP
- \fB\-q\fP
- Disable messages on output.
+++ /dev/null
-commit 4fb0b5fb585e7f697914e935fe1001f752da8470
-Author: William Lallemand <wlallemand@haproxy.org>
-Date: Thu Jun 13 11:51:09 2019 +0200
-
- MINOR: doc: add master-worker in the man page
-
- Add some information about the master-worker in the man page.
-
- Should be backported in every version since 1.8.
-
- (cherry picked from commit 95635ddac8c29859d297e8ba33174e71efd5fc47)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit d7a0c4695f00765dc03d7d6f6e17058726e84951)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
-diff --git a/doc/haproxy.1 b/doc/haproxy.1
-index cfed2cf7..2a23674f 100644
---- a/doc/haproxy.1
-+++ b/doc/haproxy.1
-@@ -6,7 +6,7 @@ HAProxy \- fast and reliable http reverse proxy and load balancer
-
- .SH SYNOPSIS
-
--haproxy \-f <configuration\ file|dir> [\-L\ <name>] [\-n\ maxconn] [\-N\ maxconn] [\-C\ <dir>] [\-v|\-vv] [\-d] [\-D] [\-q] [\-V] [\-c] [\-p\ <pidfile>] [\-dk] [\-ds] [\-de] [\-dp] [\-db] [\-dM[<byte>]] [\-m\ <megs>] [\-x <unix_socket>] [{\-sf|\-st}\ pidlist...]
-+haproxy \-f <configuration\ file|dir> [\-L\ <name>] [\-n\ maxconn] [\-N\ maxconn] [\-C\ <dir>] [\-v|\-vv] [\-d] [\-D] [\-W] [\-Ws] [\-q] [\-V] [\-c] [\-p\ <pidfile>] [\-dk] [\-ds] [\-de] [\-dp] [\-db] [\-dM[<byte>]] [\-m\ <megs>] [\-x <unix_socket>] [{\-sf|\-st}\ pidlist...]
-
- .SH DESCRIPTION
-
-@@ -77,6 +77,16 @@ starting up.
- \fB\-D\fP
- Start in daemon mode.
-
-+.TP
-+\fB\-W\fP
-+Start in master-worker mode. Could be used either with foreground or daemon
-+mode.
-+
-+.TP
-+\fB\-Ws\fP
-+Start in master-worker mode with systemd notify support. It tells systemd when
-+the process is ready. This mode forces foreground.
-+
- .TP
- \fB\-q\fP
- Disable messages on output.
-@@ -172,6 +182,9 @@ Some signals have a special meaning for the haproxy daemon. Generally, they are
- \- \fBSIGUSR1\fP
- Tells the daemon to stop all proxies and exit once all sessions are closed. It is often referred to as the "soft-stop" signal.
- .TP
-+\- \fBSIGUSR2\fP
-+In master-worker mode, reloads the configuration and sends a soft-stop signal to old processes.
-+.TP
- \- \fBSIGTTOU\fP
- Tells the daemon to stop listening to all sockets. Used internally by \fB\-sf\fP and \fB\-st\fP.
- .TP
+++ /dev/null
-commit a27131f6e1e6c3e16e056915ba5ec2c560051296
-Author: Tim Duesterhus <tim@bastelstu.be>
-Date: Mon Jun 17 16:10:07 2019 +0200
-
- BUG/MEDIUM: compression: Set Vary: Accept-Encoding for compressed responses
-
- Make HAProxy set the `Vary: Accept-Encoding` response header if it compressed
- the server response.
-
- Technically the `Vary` header SHOULD also be set for responses that would
- normally be compressed based off the current configuration, but are not due
- to a missing or invalid `Accept-Encoding` request header or due to the
- maximum compression rate being exceeded.
-
- Not setting the header in these cases does no real harm, though: An
- uncompressed response might be returned by a Cache, even if a compressed
- one could be retrieved from HAProxy. This increases the traffic to the end
- user if the cache is unable to compress itself, but it saves another
- roundtrip to HAProxy.
-
- see the discussion on the mailing list: https://www.mail-archive.com/haproxy@formilux.org/msg34221.html
- Message-ID: 20190617121708.GA2964@1wt.eu
-
- A small issue remains: The User-Agent is not added to the `Vary` header,
- despite being relevant to the response. Adding the User-Agent header would
- make responses effectively uncacheable and it's unlikely to see a Mozilla/4
- in the wild in 2019.
-
- Add a reg-test to ensure the behaviour as described in this commit message.
-
- see issue #121
- Should be backported to all branches with compression (i.e. 1.6+).
-
- (cherry picked from commit 721d686bd10dc6993859f9026ad907753d1d2064)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit eaf650083924a697cde3379703984c5e7a5ebd41)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
- (cherry picked from commit 96942d657ec7f29a328a5759558dbaa26d8e3e53)
- Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
-
- [Cf: The patch was updated because there is no HTX in 1.8]
-
-diff --git a/reg-tests/compression/vary.vtc b/reg-tests/compression/vary.vtc
-new file mode 100644
-index 00000000..0a060e4b
---- /dev/null
-+++ b/reg-tests/compression/vary.vtc
-@@ -0,0 +1,187 @@
-+varnishtest "Compression sets Vary header"
-+
-+#REQUIRE_VERSION=1.9
-+#REQUIRE_OPTION=ZLIB|SLZ
-+
-+feature ignore_unknown_macro
-+
-+server s1 {
-+ rxreq
-+ expect req.url == "/plain/accept-encoding-gzip"
-+ expect req.http.accept-encoding == "gzip"
-+ txresp \
-+ -hdr "Content-Type: text/plain" \
-+ -bodylen 100
-+
-+ rxreq
-+ expect req.url == "/plain/accept-encoding-invalid"
-+ expect req.http.accept-encoding == "invalid"
-+ txresp \
-+ -hdr "Content-Type: text/plain" \
-+ -bodylen 100
-+
-+ rxreq
-+ expect req.url == "/plain/accept-encoding-null"
-+ expect req.http.accept-encoding == "<undef>"
-+ txresp \
-+ -hdr "Content-Type: text/plain" \
-+ -bodylen 100
-+
-+ rxreq
-+ expect req.url == "/html/accept-encoding-gzip"
-+ expect req.http.accept-encoding == "gzip"
-+ txresp \
-+ -hdr "Content-Type: text/html" \
-+ -bodylen 100
-+
-+ rxreq
-+ expect req.url == "/html/accept-encoding-invalid"
-+ expect req.http.accept-encoding == "invalid"
-+ txresp \
-+ -hdr "Content-Type: text/html" \
-+ -bodylen 100
-+
-+
-+ rxreq
-+ expect req.url == "/html/accept-encoding-null"
-+ expect req.http.accept-encoding == "<undef>"
-+ txresp \
-+ -hdr "Content-Type: text/html" \
-+ -bodylen 100
-+
-+ rxreq
-+ expect req.url == "/dup-etag/accept-encoding-gzip"
-+ expect req.http.accept-encoding == "gzip"
-+ txresp \
-+ -hdr "Content-Type: text/plain" \
-+ -hdr "ETag: \"123\"" \
-+ -hdr "ETag: \"123\"" \
-+ -bodylen 100
-+} -repeat 2 -start
-+
-+
-+haproxy h1 -conf {
-+ defaults
-+ mode http
-+ ${no-htx} option http-use-htx
-+ timeout connect 1s
-+ timeout client 1s
-+ timeout server 1s
-+
-+ frontend fe-gzip
-+ bind "fd@${fe_gzip}"
-+ default_backend be-gzip
-+
-+ backend be-gzip
-+ compression algo gzip
-+ compression type text/plain
-+ server www ${s1_addr}:${s1_port}
-+
-+ frontend fe-nothing
-+ bind "fd@${fe_nothing}"
-+ default_backend be-nothing
-+
-+ backend be-nothing
-+ server www ${s1_addr}:${s1_port}
-+} -start
-+
-+client c1 -connect ${h1_fe_gzip_sock} {
-+ txreq -url "/plain/accept-encoding-gzip" \
-+ -hdr "Accept-Encoding: gzip"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.content-encoding == "gzip"
-+ expect resp.http.vary == "Accept-Encoding"
-+ gunzip
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/plain/accept-encoding-invalid" \
-+ -hdr "Accept-Encoding: invalid"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/plain/accept-encoding-null"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/html/accept-encoding-gzip" \
-+ -hdr "Accept-Encoding: gzip"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/html/accept-encoding-invalid" \
-+ -hdr "Accept-Encoding: invalid"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/html/accept-encoding-null"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/dup-etag/accept-encoding-gzip" \
-+ -hdr "Accept-Encoding: gzip"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+} -run
-+
-+# This Client duplicates c1, against the "nothing" frontend, ensuring no Vary header is ever set.
-+client c2 -connect ${h1_fe_nothing_sock} {
-+ txreq -url "/plain/accept-encoding-gzip" \
-+ -hdr "Accept-Encoding: gzip"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/plain/accept-encoding-invalid" \
-+ -hdr "Accept-Encoding: invalid"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/plain/accept-encoding-null"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/html/accept-encoding-gzip" \
-+ -hdr "Accept-Encoding: gzip"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/html/accept-encoding-invalid" \
-+ -hdr "Accept-Encoding: invalid"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/html/accept-encoding-null"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+
-+ txreq -url "/dup-etag/accept-encoding-gzip" \
-+ -hdr "Accept-Encoding: gzip"
-+ rxresp
-+ expect resp.status == 200
-+ expect resp.http.vary == "<undef>"
-+ expect resp.bodylen == 100
-+} -run
-diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c
-index b93ff69e..b48a4491 100644
---- a/src/flt_http_comp.c
-+++ b/src/flt_http_comp.c
-@@ -555,6 +555,9 @@ select_compression_response_header(struct comp_state *st, struct stream *s, stru
- if (!(msg->flags & HTTP_MSGF_TE_CHNK))
- http_header_add_tail2(&txn->rsp, &txn->hdr_idx, "Transfer-Encoding: chunked", 26);
-
-+ /* add Vary header */
-+ if (http_header_add_tail2(&txn->rsp, &txn->hdr_idx, "Vary: Accept-Encoding", 21) < 0)
-+ goto fail;
- /*
- * Add Content-Encoding header when it's not identity encoding.
- * RFC 2616 : Identity encoding: This content-coding is used only in the
+++ /dev/null
---- a/src/ssl_sock.c
-+++ b/src/ssl_sock.c
-@@ -39,6 +39,7 @@
- #include <netdb.h>
- #include <netinet/tcp.h>
-
-+#include <openssl/bn.h>
- #include <openssl/crypto.h>
- #include <openssl/ssl.h>
- #include <openssl/x509.h>
-@@ -60,6 +61,17 @@
- #include <openssl/async.h>
- #endif
-
-+#ifndef OPENSSL_VERSION
-+#define OPENSSL_VERSION SSLEAY_VERSION
-+#define OpenSSL_version(x) SSLeay_version(x)
-+#define OpenSSL_version_num SSLeay
-+#endif
-+
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
-+#define X509_getm_notBefore X509_get_notBefore
-+#define X509_getm_notAfter X509_get_notAfter
-+#endif
-+
- #include <import/lru.h>
- #include <import/xxhash.h>
-
-@@ -217,7 +229,7 @@ static struct {
- .capture_cipherlist = 0,
- };
-
--#ifdef USE_THREAD
-+#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
-
- static HA_RWLOCK_T *ssl_rwlocks;
-
-@@ -1716,8 +1728,8 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL
- ASN1_INTEGER_set(X509_get_serialNumber(newcrt), HA_ATOMIC_ADD(&ssl_ctx_serial, 1));
-
- /* Set duration for the certificate */
-- if (!X509_gmtime_adj(X509_get_notBefore(newcrt), (long)-60*60*24) ||
-- !X509_gmtime_adj(X509_get_notAfter(newcrt),(long)60*60*24*365))
-+ if (!X509_gmtime_adj(X509_getm_notBefore(newcrt), (long)-60*60*24) ||
-+ !X509_gmtime_adj(X509_getm_notAfter(newcrt),(long)60*60*24*365))
- goto mkcert_error;
-
- /* set public key in the certificate */
-@@ -6299,7 +6311,7 @@ smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char
- goto out;
-
- smp_trash = get_trash_chunk();
-- if (ssl_sock_get_time(X509_get_notAfter(crt), smp_trash) <= 0)
-+ if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
- goto out;
-
- smp->data.u.str = *smp_trash;
-@@ -6399,7 +6411,7 @@ smp_fetch_ssl_x_notbefore(const struct a
- goto out;
-
- smp_trash = get_trash_chunk();
-- if (ssl_sock_get_time(X509_get_notBefore(crt), smp_trash) <= 0)
-+ if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
- goto out;
-
- smp->data.u.str = *smp_trash;
-@@ -8977,7 +8989,9 @@ static void __ssl_sock_init(void)
- #endif
-
- xprt_register(XPRT_SSL, &ssl_sock);
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL_library_init();
-+#endif
- #if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION))
- cm = SSL_COMP_get_compression_methods();
- i = sk_SSL_COMP_num(cm);
-@@ -8986,7 +9000,7 @@ static void __ssl_sock_init(void)
- }
- #endif
-
--#ifdef USE_THREAD
-+#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
- ssl_locking_init();
- #endif
- #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
-@@ -9015,8 +9029,8 @@ static void __ssl_sock_init(void)
- #else /* OPENSSL_IS_BORINGSSL */
- OPENSSL_VERSION_TEXT
- "\nRunning on OpenSSL version : %s%s",
-- SSLeay_version(SSLEAY_VERSION),
-- ((OPENSSL_VERSION_NUMBER ^ SSLeay()) >> 8) ? " (VERSIONS DIFFER!)" : "");
-+ OpenSSL_version(OPENSSL_VERSION),
-+ ((OPENSSL_VERSION_NUMBER ^ OpenSSL_version_num()) >> 8) ? " (VERSIONS DIFFER!)" : "");
- #endif
- memprintf(&ptr, "%s\nOpenSSL library supports TLS extensions : "
- #if OPENSSL_VERSION_NUMBER < 0x00907000L
-@@ -9107,12 +9121,14 @@ static void __ssl_sock_deinit(void)
- }
- #endif
-
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
- ERR_remove_state(0);
- ERR_free_strings();
-
- EVP_cleanup();
-+#endif
-
--#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-+#if OPENSSL_VERSION_NUMBER >= 0x00907000L && OPENSSL_VERSION_NUMBER < 0x10100000L
- CRYPTO_cleanup_all_ex_data();
- #endif
- }