Merge pull request #10156 from gladiac1337/haproxy-1.8.21-openwrt-18.06

[openwrt-18.06] haproxy: Update HAProxy to v1.8.21
This commit is contained in:
Hannu Nyman 2019-10-05 17:17:46 +03:00 committed by GitHub
commit 5452bb8332
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 594 additions and 2853 deletions

View file

@ -10,12 +10,12 @@
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

View file

@ -1,7 +1,7 @@
#!/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

View file

@ -1,40 +0,0 @@
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)) {

View file

@ -0,0 +1,33 @@
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;
}

View file

@ -1,83 +0,0 @@
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;
}

View file

@ -0,0 +1,32 @@
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);
}

View file

@ -0,0 +1,33 @@
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).

View file

@ -1,71 +0,0 @@
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;
}

View file

@ -0,0 +1,77 @@
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;
- }
}

View file

@ -1,38 +0,0 @@
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

View file

@ -0,0 +1,39 @@
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.
*/

View file

@ -1,36 +0,0 @@
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) {

View file

@ -0,0 +1,108 @@
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)

View file

@ -1,23 +0,0 @@
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>

View file

@ -1,67 +0,0 @@
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);

View file

@ -0,0 +1,32 @@
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

View file

@ -1,79 +0,0 @@
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;

View file

@ -0,0 +1,50 @@
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;

View file

@ -0,0 +1,31 @@
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

View file

@ -1,44 +0,0 @@
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))

View file

@ -0,0 +1,39 @@
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));

View file

@ -1,34 +0,0 @@
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;
}

View file

@ -0,0 +1,57 @@
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

View file

@ -1,54 +0,0 @@
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) \

View file

@ -1,116 +0,0 @@
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 */
};

View file

@ -0,0 +1,60 @@
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;

View file

@ -1,81 +0,0 @@
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 },

View file

@ -1,37 +0,0 @@
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 */

View file

@ -1,44 +0,0 @@
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)

View file

@ -1,925 +0,0 @@
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"}

View file

@ -1,53 +0,0 @@
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

View file

@ -1,46 +0,0 @@
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();

View file

@ -1,54 +0,0 @@
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);

View file

@ -1,43 +0,0 @@
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:

View file

@ -1,71 +0,0 @@
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");

View file

@ -1,133 +0,0 @@
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;
}

View file

@ -1,193 +0,0 @@
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. */

View file

@ -1,44 +0,0 @@
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;

View file

@ -1,73 +0,0 @@
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);
}
}

View file

@ -1,34 +0,0 @@
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;

View file

@ -1,30 +0,0 @@
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.

View file

@ -1,55 +0,0 @@
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

View file

@ -1,249 +0,0 @@
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