[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#856451: marked as done (unblock: haproxy/1.7.3-1)



Your message dated Thu, 02 Mar 2017 17:20:27 +0000
with message-id <E1cjUOx-00026t-K1@respighi.debian.org>
and subject line unblock haproxy
has caused the Debian Bug report #856451,
regarding unblock: haproxy/1.7.3-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
856451: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=856451
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hey!

We would like to upload HAProxy 1.7.3 to unstable. This is mostly a
bugfix only release (1.7 is the current stable branch). Here is the
changelog:

    - BUG/MINOR: stream: Fix how backend-specific analyzers are set on a stream
    - BUILD: ssl: fix build on OpenSSL 1.0.0
    - BUILD: ssl: silence a warning reported for ERR_remove_state()
    - BUILD: ssl: eliminate warning with OpenSSL 1.1.0 regarding RAND_pseudo_bytes()
    - BUG/MEDIUM: tcp: don't poll for write when connect() succeeds
    - BUG/MINOR: unix: fix connect's polling in case no data are scheduled
    - DOC: lua: improve links
    - BUG/MINOR: lua: Map.end are not reliable because "end" is a reserved keyword
    - MINOR: dns: give ability to dns_init_resolvers() to close a socket when requested
    - BUG/MAJOR: dns: restart sockets after fork()
    - MINOR: chunks: implement a simple dynamic allocator for trash buffers
    - BUG/MEDIUM: http: prevent redirect from overwriting a buffer
    - BUG/MEDIUM: filters: Do not truncate HTTP response when body length is undefined
    - BUG/MEDIUM: http: Prevent replace-header from overwriting a buffer
    - BUG/MINOR: http: Return an error when a replace-header rule failed on the response
    - BUG/MINOR: sendmail: The return of vsnprintf is not cleanly tested
    - BUG/MAJOR: lua segmentation fault when the request is like 'GET ?arg=val HTTP/1.1'
    - BUG/MEDIUM: config: reject anything but "if" or "unless" after a use-backend rule
    - MINOR: http: don't close when redirect location doesn't start with "/"

The diffstat:

 CHANGELOG                      |  21 +++++++++
 README                         |   2 +-
 VERDATE                        |   2 +-
 VERSION                        |   2 +-
 doc/configuration.txt          |   2 +-
 doc/lua-api/index.rst          | 141 +++++++++++++++++++++++++++++++++++----------------------
 examples/haproxy.spec          |   5 ++-
 include/common/chunk.h         |  13 ++++++
 include/proto/dns.h            |   2 +-
 include/proto/openssl-compat.h |  44 +++++++++++++-----
 src/cfgparse.c                 |   6 +++
 src/checks.c                   |   2 +-
 src/chunk.c                    |  25 ++++++++++-
 src/dns.c                      |  18 +++++++-
 src/haproxy.c                  |   7 ++-
 src/hlua.c                     |  34 ++++++++------
 src/proto_http.c               | 169 ++++++++++++++++++++++++++++++++++++---------------------------------
 src/proto_tcp.c                |  30 ++++++++++---
 src/proto_uxst.c               |  27 ++++++-----
 src/proxy.c                    |   2 +-
 20 files changed, 368 insertions(+), 186 deletions(-)

And attached is the diff for "src/" only. Does it sound reasonable?

unblock haproxy/1.7.3-1

- -- System Information:
Debian Release: 9.0
  APT prefers unstable-debug
  APT policy: (500, 'unstable-debug'), (500, 'unstable'), (500, 'testing'), (101, 'experimental-debug'), (101, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.9.0-2-amd64 (SMP w/4 CPU cores)
Locale: LANG=fr_FR.utf8, LC_CTYPE=fr_FR.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)

-----BEGIN PGP SIGNATURE-----

iQJGBAEBCAAwFiEErvI0h2bzccaJpzYAlaQv6DU1JfkFAli2ccwSHGJlcm5hdEBk
ZWJpYW4ub3JnAAoJEJWkL+g1NSX5izAP/34k9DBU01v7/NoQxrnToIZg4NCt79a/
OwiA2wjltYMcqFzuirA5GkDw+7U6GWfob72MbbMvsXaw6qW3bI2uJMTR+QPaObVQ
l8ItHH8hHMP9d+r/lXCPuwfgpHEEu1OOPStofC0l6bz0tPrW3r3ftNjIxVJfc0yf
nCm5iGM1zh2GlLPbXaSzOqvVkSRm+GG6zXDeH9nsv9DbvT/uZkESTX66eVwgl/FS
MM5g/bwQqdsR9sSpL635Syq/Mahe5VFMG9xZ53YJS+K+XGV++53d7vxQkVOBlJo8
DW4W0USVM3gB6WRNsKR0VthE45cEuwbtIe5CeN7xQO5j9HecuLQ/dCU5REJZ5O3J
Y5ks4RRspIFPbfLv70i+B1gnGzopM1HltXMVlx2AkHxr32sdrrWxGF2+gS6qH2fS
8XkD0e4QUgnLUNmoM+W6HHqYiU63qI/gLf2UdvtlxjS4c5UygnauWqgRoOmuVc9O
1esvWTsmr7LV3adysC3gaa4DUjVqP69VS2vdl+gVEBmbwzfTwLL51oNnEmMJXIpW
RukMFWktkh30KVMQQE7ZzHAL9/Zh3BxWBccGfyimG2JHV8PfRYPRHtAXqKhEbjAK
MFDNue551ZknmdunGhG3KeobyYpCtGzzkfRRgfUw50Ddt2WhF7uZKz14f8QZMvmE
aSB34fQPyX5S
=FdZa
-----END PGP SIGNATURE-----
diff --git a/src/cfgparse.c b/src/cfgparse.c
index db8feebbcd11..fc6e1497f129 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -3984,6 +3984,12 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
 
 			err_code |= warnif_cond_conflicts(cond, SMP_VAL_FE_SET_BCK, file, linenum);
 		}
+		else if (*args[2]) {
+			Alert("parsing [%s:%d] : unexpected keyword '%s' after switching rule, only 'if' and 'unless' are allowed.\n",
+			      file, linenum, args[2]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
 
 		rule = calloc(1, sizeof(*rule));
 		if (!rule) {
diff --git a/src/checks.c b/src/checks.c
index 53513caa411d..1e43dec3f02a 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -3407,7 +3407,7 @@ void send_email_alert(struct server *s, int level, const char *format, ...)
 	len = vsnprintf(buf, sizeof(buf), format, argp);
 	va_end(argp);
 
-	if (len < 0) {
+	if (len < 0 || len >= sizeof(buf)) {
 		Alert("Email alert [%s] could not format message\n", p->id);
 		return;
 	}
diff --git a/src/chunk.c b/src/chunk.c
index 7134fead3503..60902127c64c 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -29,6 +29,9 @@ static int trash_size;
 static char *trash_buf1;
 static char *trash_buf2;
 
+/* the trash pool for reentrant allocations */
+struct pool_head *pool2_trash = NULL;
+
 /*
 * Returns a pre-allocated and initialized trash chunk that can be used for any
 * type of conversion. Two chunks and their respective buffers are alternatively
@@ -63,7 +66,8 @@ int alloc_trash_buffers(int bufsize)
 	trash_size = bufsize;
 	trash_buf1 = (char *)my_realloc2(trash_buf1, bufsize);
 	trash_buf2 = (char *)my_realloc2(trash_buf2, bufsize);
-	return trash_buf1 && trash_buf2;
+	pool2_trash = create_pool("trash", sizeof(struct chunk) + bufsize, MEM_F_EXACT);
+	return trash_buf1 && trash_buf2 && pool2_trash;
 }
 
 /*
@@ -77,6 +81,25 @@ void free_trash_buffers(void)
 	trash_buf1 = NULL;
 }
 
+/*
+ * Allocate a trash chunk from the reentrant pool. The buffer starts at the
+ * end of the chunk. This chunk must be freed using free_trash_chunk(). This
+ * call may fail and the caller is responsible for checking that the returned
+ * pointer is not NULL.
+ */
+struct chunk *alloc_trash_chunk(void)
+{
+	struct chunk *chunk;
+
+	chunk = pool_alloc2(pool2_trash);
+	if (chunk) {
+		char *buf = (char *)chunk + sizeof(struct chunk);
+		*buf = 0;
+		chunk_init(chunk, buf, pool2_trash->size - sizeof(struct chunk));
+	}
+	return chunk;
+}
+
 /*
  * Does an snprintf() at the beginning of chunk <chk>, respecting the limit of
  * at most chk->size chars. If the chk->len is over, nothing is added. Returns
diff --git a/src/dns.c b/src/dns.c
index 012fcede4f9a..83a1ef4ffe73 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -919,11 +919,13 @@ unsigned short dns_response_get_query_id(unsigned char *resp)
  * parses resolvers sections and initializes:
  *  - task (time events) for each resolvers section
  *  - the datagram layer (network IO events) for each nameserver
+ * It takes one argument:
+ *  - close_first takes 2 values: 0 or 1. If 1, the connection is closed first.
  * returns:
  *  0 in case of error
  *  1 when no error
  */
-int dns_init_resolvers(void)
+int dns_init_resolvers(int close_socket)
 {
 	struct dns_resolvers *curr_resolvers;
 	struct dns_nameserver *curnameserver;
@@ -961,7 +963,19 @@ int dns_init_resolvers(void)
 		curr_resolvers->t = t;
 
 		list_for_each_entry(curnameserver, &curr_resolvers->nameserver_list, list) {
-			if ((dgram = calloc(1, sizeof(*dgram))) == NULL) {
+		        dgram = NULL;
+
+			if (close_socket == 1) {
+				if (curnameserver->dgram) {
+					close(curnameserver->dgram->t.sock.fd);
+					memset(curnameserver->dgram, '\0', sizeof(*dgram));
+					dgram = curnameserver->dgram;
+				}
+			}
+
+			/* allocate memory only if it has not already been allocated
+			 * by a previous call to this function */
+			if (!dgram && (dgram = calloc(1, sizeof(*dgram))) == NULL) {
 				Alert("Starting [%s/%s] nameserver: out of memory.\n", curr_resolvers->id,
 						curnameserver->id);
 				return 0;
diff --git a/src/haproxy.c b/src/haproxy.c
index 995b3a630b76..449ab054f48a 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1309,7 +1309,7 @@ void init(int argc, char **argv)
 		exit(1);
 
 	/* initialize structures for name resolution */
-	if (!dns_init_resolvers())
+	if (!dns_init_resolvers(0))
 		exit(1);
 
 	free(err_msg);
@@ -1685,6 +1685,7 @@ void deinit(void)
 	pool_destroy2(pool2_stream);
 	pool_destroy2(pool2_session);
 	pool_destroy2(pool2_connection);
+	pool_destroy2(pool2_trash);
 	pool_destroy2(pool2_buffer);
 	pool_destroy2(pool2_requri);
 	pool_destroy2(pool2_task);
@@ -2090,6 +2091,10 @@ int main(int argc, char **argv)
 		fork_poller();
 	}
 
+	/* initialize structures for name resolution */
+	if (!dns_init_resolvers(1))
+		exit(1);
+
 	protocol_enable_all();
 	/*
 	 * That's it : the central polling loop. Run until we stop.
diff --git a/src/hlua.c b/src/hlua.c
index 133756605093..2f9c8b7b8242 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -3551,22 +3551,24 @@ static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
 
 	/* Get path and qs */
 	path = http_get_path(txn);
-	end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
-	p = path;
-	while (p < end && *p != '?')
-		p++;
+	if (path) {
+		end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
+		p = path;
+		while (p < end && *p != '?')
+			p++;
 
-	/* Stores the request path. */
-	lua_pushstring(L, "path");
-	lua_pushlstring(L, path, p - path);
-	lua_settable(L, -3);
+		/* Stores the request path. */
+		lua_pushstring(L, "path");
+		lua_pushlstring(L, path, p - path);
+		lua_settable(L, -3);
 
-	/* Stores the query string. */
-	lua_pushstring(L, "qs");
-	if (*p == '?')
-		p++;
-	lua_pushlstring(L, p, end - p);
-	lua_settable(L, -3);
+		/* Stores the query string. */
+		lua_pushstring(L, "qs");
+		if (*p == '?')
+			p++;
+		lua_pushlstring(L, p, end - p);
+		lua_settable(L, -3);
+	}
 
 	/* Stores the request path. */
 	lua_pushstring(L, "length");
@@ -7008,6 +7010,10 @@ void hlua_init(void)
 	/* register pattern types. */
 	for (i=0; i<PAT_MATCH_NUM; i++)
 		hlua_class_const_int(gL.T, pat_match_names[i], i);
+	for (i=0; i<PAT_MATCH_NUM; i++) {
+		snprintf(trash.str, trash.size, "_%s", pat_match_names[i]);
+		hlua_class_const_int(gL.T, trash.str, i);
+	}
 
 	/* register constructor. */
 	hlua_class_function(gL.T, "new", hlua_map_new);
diff --git a/src/proto_http.c b/src/proto_http.c
index dd5c731ca3a3..eb53b7235a3a 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3419,13 +3419,22 @@ static int http_transform_header(struct stream* s, struct http_msg *msg,
                                  struct list *fmt, struct my_regex *re,
                                  int action)
 {
-	struct chunk *replace = get_trash_chunk();
+	struct chunk *replace;
+	int ret = -1;
+
+	replace = alloc_trash_chunk();
+	if (!replace)
+		goto leave;
 
 	replace->len = build_logline(s, replace->str, replace->size, fmt);
 	if (replace->len >= replace->size - 1)
-		return -1;
+		goto leave;
+
+	ret = http_transform_header_str(s, msg, name, name_len, replace->str, re, action);
 
-	return http_transform_header_str(s, msg, name, name_len, replace->str, re, action);
+  leave:
+	free_trash_chunk(replace);
+	return ret;
 }
 
 /* Executes the http-request rules <rules> for stream <s>, proxy <px> and
@@ -3814,7 +3823,7 @@ resume_execution:
 			                          rule->arg.hdr_add.name_len,
 			                          &rule->arg.hdr_add.fmt,
 			                          &rule->arg.hdr_add.re, rule->action))
-				return HTTP_RULE_RES_STOP; /* note: we should report an error here */
+				return HTTP_RULE_RES_BADREQ;
 			break;
 
 		case ACT_HTTP_DEL_HDR:
@@ -4023,7 +4032,12 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
 	struct http_msg *req = &txn->req;
 	struct http_msg *res = &txn->rsp;
 	const char *msg_fmt;
-	const char *location;
+	struct chunk *chunk;
+	int ret = 0;
+
+	chunk = alloc_trash_chunk();
+	if (!chunk)
+		goto leave;
 
 	/* build redirect message */
 	switch(rule->code) {
@@ -4045,10 +4059,8 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
 		break;
 	}
 
-	if (unlikely(!chunk_strcpy(&trash, msg_fmt)))
-		return 0;
-
-	location = trash.str + trash.len;
+	if (unlikely(!chunk_strcpy(chunk, msg_fmt)))
+		goto leave;
 
 	switch(rule->type) {
 	case REDIRECT_TYPE_SCHEME: {
@@ -4087,40 +4099,40 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
 
 		if (rule->rdr_str) { /* this is an old "redirect" rule */
 			/* check if we can add scheme + "://" + host + path */
-			if (trash.len + rule->rdr_len + 3 + hostlen + pathlen > trash.size - 4)
-				return 0;
+			if (chunk->len + rule->rdr_len + 3 + hostlen + pathlen > chunk->size - 4)
+				goto leave;
 
 			/* add scheme */
-			memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
-			trash.len += rule->rdr_len;
+			memcpy(chunk->str + chunk->len, rule->rdr_str, rule->rdr_len);
+			chunk->len += rule->rdr_len;
 		}
 		else {
 			/* add scheme with executing log format */
-			trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
+			chunk->len += build_logline(s, chunk->str + chunk->len, chunk->size - chunk->len, &rule->rdr_fmt);
 
 			/* check if we can add scheme + "://" + host + path */
-			if (trash.len + 3 + hostlen + pathlen > trash.size - 4)
-				return 0;
+			if (chunk->len + 3 + hostlen + pathlen > chunk->size - 4)
+				goto leave;
 		}
 		/* add "://" */
-		memcpy(trash.str + trash.len, "://", 3);
-		trash.len += 3;
+		memcpy(chunk->str + chunk->len, "://", 3);
+		chunk->len += 3;
 
 		/* add host */
-		memcpy(trash.str + trash.len, host, hostlen);
-		trash.len += hostlen;
+		memcpy(chunk->str + chunk->len, host, hostlen);
+		chunk->len += hostlen;
 
 		/* add path */
-		memcpy(trash.str + trash.len, path, pathlen);
-		trash.len += pathlen;
+		memcpy(chunk->str + chunk->len, path, pathlen);
+		chunk->len += pathlen;
 
 		/* append a slash at the end of the location if needed and missing */
-		if (trash.len && trash.str[trash.len - 1] != '/' &&
+		if (chunk->len && chunk->str[chunk->len - 1] != '/' &&
 		    (rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
-			if (trash.len > trash.size - 5)
-				return 0;
-			trash.str[trash.len] = '/';
-			trash.len++;
+			if (chunk->len > chunk->size - 5)
+				goto leave;
+			chunk->str[chunk->len] = '/';
+			chunk->len++;
 		}
 
 		break;
@@ -4149,38 +4161,38 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
 		}
 
 		if (rule->rdr_str) { /* this is an old "redirect" rule */
-			if (trash.len + rule->rdr_len + pathlen > trash.size - 4)
-				return 0;
+			if (chunk->len + rule->rdr_len + pathlen > chunk->size - 4)
+				goto leave;
 
 			/* add prefix. Note that if prefix == "/", we don't want to
 			 * add anything, otherwise it makes it hard for the user to
 			 * configure a self-redirection.
 			 */
 			if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
-				memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
-				trash.len += rule->rdr_len;
+				memcpy(chunk->str + chunk->len, rule->rdr_str, rule->rdr_len);
+				chunk->len += rule->rdr_len;
 			}
 		}
 		else {
 			/* add prefix with executing log format */
-			trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
+			chunk->len += build_logline(s, chunk->str + chunk->len, chunk->size - chunk->len, &rule->rdr_fmt);
 
 			/* Check length */
-			if (trash.len + pathlen > trash.size - 4)
-				return 0;
+			if (chunk->len + pathlen > chunk->size - 4)
+				goto leave;
 		}
 
 		/* add path */
-		memcpy(trash.str + trash.len, path, pathlen);
-		trash.len += pathlen;
+		memcpy(chunk->str + chunk->len, path, pathlen);
+		chunk->len += pathlen;
 
 		/* append a slash at the end of the location if needed and missing */
-		if (trash.len && trash.str[trash.len - 1] != '/' &&
+		if (chunk->len && chunk->str[chunk->len - 1] != '/' &&
 		    (rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
-			if (trash.len > trash.size - 5)
-				return 0;
-			trash.str[trash.len] = '/';
-			trash.len++;
+			if (chunk->len > chunk->size - 5)
+				goto leave;
+			chunk->str[chunk->len] = '/';
+			chunk->len++;
 		}
 
 		break;
@@ -4188,59 +4200,54 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
 	case REDIRECT_TYPE_LOCATION:
 	default:
 		if (rule->rdr_str) { /* this is an old "redirect" rule */
-			if (trash.len + rule->rdr_len > trash.size - 4)
-				return 0;
+			if (chunk->len + rule->rdr_len > chunk->size - 4)
+				goto leave;
 
 			/* add location */
-			memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
-			trash.len += rule->rdr_len;
+			memcpy(chunk->str + chunk->len, rule->rdr_str, rule->rdr_len);
+			chunk->len += rule->rdr_len;
 		}
 		else {
 			/* add location with executing log format */
-			trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
+			chunk->len += build_logline(s, chunk->str + chunk->len, chunk->size - chunk->len, &rule->rdr_fmt);
 
 			/* Check left length */
-			if (trash.len > trash.size - 4)
-				return 0;
+			if (chunk->len > chunk->size - 4)
+				goto leave;
 		}
 		break;
 	}
 
 	if (rule->cookie_len) {
-		memcpy(trash.str + trash.len, "\r\nSet-Cookie: ", 14);
-		trash.len += 14;
-		memcpy(trash.str + trash.len, rule->cookie_str, rule->cookie_len);
-		trash.len += rule->cookie_len;
+		memcpy(chunk->str + chunk->len, "\r\nSet-Cookie: ", 14);
+		chunk->len += 14;
+		memcpy(chunk->str + chunk->len, rule->cookie_str, rule->cookie_len);
+		chunk->len += rule->cookie_len;
 	}
 
-	/* add end of headers and the keep-alive/close status.
-	 * We may choose to set keep-alive if the Location begins
-	 * with a slash, because the client will come back to the
-	 * same server.
-	 */
+	/* add end of headers and the keep-alive/close status. */
 	txn->status = rule->code;
 	/* let's log the request time */
 	s->logs.tv_request = now;
 
-	if (*location == '/' &&
-	    (req->flags & HTTP_MSGF_XFER_LEN) &&
+	if ((req->flags & HTTP_MSGF_XFER_LEN) &&
 	    ((!(req->flags & HTTP_MSGF_TE_CHNK) && !req->body_len) || (req->msg_state == HTTP_MSG_DONE)) &&
 	    ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
 	     (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)) {
 		/* keep-alive possible */
 		if (!(req->flags & HTTP_MSGF_VER_11)) {
 			if (unlikely(txn->flags & TX_USE_PX_CONN)) {
-				memcpy(trash.str + trash.len, "\r\nProxy-Connection: keep-alive", 30);
-				trash.len += 30;
+				memcpy(chunk->str + chunk->len, "\r\nProxy-Connection: keep-alive", 30);
+				chunk->len += 30;
 			} else {
-				memcpy(trash.str + trash.len, "\r\nConnection: keep-alive", 24);
-				trash.len += 24;
+				memcpy(chunk->str + chunk->len, "\r\nConnection: keep-alive", 24);
+				chunk->len += 24;
 			}
 		}
-		memcpy(trash.str + trash.len, "\r\n\r\n", 4);
-		trash.len += 4;
-		FLT_STRM_CB(s, flt_http_reply(s, txn->status, &trash));
-		bo_inject(res->chn, trash.str, trash.len);
+		memcpy(chunk->str + chunk->len, "\r\n\r\n", 4);
+		chunk->len += 4;
+		FLT_STRM_CB(s, flt_http_reply(s, txn->status, chunk));
+		bo_inject(res->chn, chunk->str, chunk->len);
 		/* "eat" the request */
 		bi_fast_delete(req->chn->buf, req->sov);
 		req->next -= req->sov;
@@ -4255,13 +4262,13 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
 	} else {
 		/* keep-alive not possible */
 		if (unlikely(txn->flags & TX_USE_PX_CONN)) {
-			memcpy(trash.str + trash.len, "\r\nProxy-Connection: close\r\n\r\n", 29);
-			trash.len += 29;
+			memcpy(chunk->str + chunk->len, "\r\nProxy-Connection: close\r\n\r\n", 29);
+			chunk->len += 29;
 		} else {
-			memcpy(trash.str + trash.len, "\r\nConnection: close\r\n\r\n", 23);
-			trash.len += 23;
+			memcpy(chunk->str + chunk->len, "\r\nConnection: close\r\n\r\n", 23);
+			chunk->len += 23;
 		}
-		http_reply_and_close(s, txn->status, &trash);
+		http_reply_and_close(s, txn->status, chunk);
 		req->chn->analysers &= AN_REQ_FLT_END;
 	}
 
@@ -4270,7 +4277,10 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s
 	if (!(s->flags & SF_FINST_MASK))
 		s->flags |= SF_FINST_R;
 
-	return 1;
+	ret = 1;
+ leave:
+	free_trash_chunk(chunk);
+	return ret;
 }
 
 /* This stream analyser runs all HTTP request processing which is common to
@@ -6820,7 +6830,7 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
 	}
 
  skip_header_mangling:
-	if ((msg->flags & HTTP_MSGF_XFER_LEN) || HAS_FILTERS(s) ||
+	if ((msg->flags & HTTP_MSGF_XFER_LEN) || HAS_DATA_FILTERS(s, rep) ||
 	    (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN) {
 		rep->analysers &= ~AN_RES_FLT_XFER_DATA;
 		rep->analysers |= AN_RES_HTTP_XFER_BODY;
@@ -6971,8 +6981,8 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
 	 * keep-alive is set on the client side or if there are filters
 	 * registered on the stream, we don't want to forward a close
 	 */
-	if ((msg->flags & HTTP_MSGF_TE_CHNK) || !msg->body_len ||
-	    HAS_FILTERS(s) ||
+	if ((msg->flags & HTTP_MSGF_TE_CHNK) || !(msg->flags & HTTP_MSGF_XFER_LEN) ||
+	    HAS_DATA_FILTERS(s, res) ||
 	    (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
 	    (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)
 		channel_dont_close(res);
@@ -7064,11 +7074,10 @@ http_msg_forward_body(struct stream *s, struct http_msg *msg)
 		goto missing_data_or_waiting;
 	}
 
-	if (!(msg->flags & HTTP_MSGF_XFER_LEN) && !(chn->flags & CF_SHUTR) &&
-	    HAS_DATA_FILTERS(s, chn)) {
-		/* The server still sending data that should be filtered */
+	/* The server still sending data that should be filtered */
+	if (!(msg->flags & HTTP_MSGF_XFER_LEN) && !(chn->flags & CF_SHUTR))
 		goto missing_data_or_waiting;
-	}
+
 	msg->msg_state = HTTP_MSG_ENDING;
 
   ending:
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index f6d8ca13c7dc..c04f2767f0ef 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -474,10 +474,16 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
 	if (global.tune.server_rcvbuf)
                 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
 
-	if ((connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) == -1) &&
-	    (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
-
-		if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) {
+	if (connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) == -1) {
+		if (errno == EINPROGRESS || errno == EALREADY) {
+			/* common case, let's wait for connect status */
+			conn->flags |= CO_FL_WAIT_L4_CONN;
+		}
+		else if (errno == EISCONN) {
+			/* should normally not happen but if so, indicates that it's OK */
+			conn->flags &= ~CO_FL_WAIT_L4_CONN;
+		}
+		else if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) {
 			char *msg;
 			if (errno == EAGAIN || errno == EADDRNOTAVAIL) {
 				msg = "no free ports";
@@ -514,6 +520,10 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
 			return SF_ERR_SRVCL;
 		}
 	}
+	else {
+		/* connect() == 0, this is great! */
+		conn->flags &= ~CO_FL_WAIT_L4_CONN;
+	}
 
 	conn->flags |= CO_FL_ADDR_TO_SET;
 
@@ -523,7 +533,6 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
 
 	conn_ctrl_init(conn);       /* registers the FD */
 	fdtab[fd].linger_risk = 1;  /* close hard if needed */
-	conn_sock_want_send(conn);  /* for connect status */
 
 	if (conn_xprt_init(conn) < 0) {
 		conn_force_close(conn);
@@ -531,6 +540,17 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
 		return SF_ERR_RESOURCE;
 	}
 
+	if (conn->flags & (CO_FL_HANDSHAKE | CO_FL_WAIT_L4_CONN)) {
+		conn_sock_want_send(conn);  /* for connect status, proxy protocol or SSL */
+	}
+	else {
+		/* If there's no more handshake, we need to notify the data
+		 * layer when the connection is already OK otherwise we'll have
+		 * no other opportunity to do it later (eg: health checks).
+		 */
+		data = 1;
+	}
+
 	if (data)
 		conn_data_want_send(conn);  /* prepare to send data if any */
 
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 5c8f9d4b2770..27ff0fa40786 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -495,12 +495,12 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
                 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
 
 	if (connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) == -1) {
-		if (errno == EALREADY || errno == EISCONN) {
-			conn->flags &= ~CO_FL_WAIT_L4_CONN;
-		}
-		else if (errno == EINPROGRESS) {
+		if (errno == EINPROGRESS || errno == EALREADY) {
 			conn->flags |= CO_FL_WAIT_L4_CONN;
 		}
+		else if (errno == EISCONN) {
+			conn->flags &= ~CO_FL_WAIT_L4_CONN;
+		}
 		else if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) {
 			char *msg;
 			if (errno == EAGAIN || errno == EADDRNOTAVAIL) {
@@ -533,13 +533,9 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
 	}
 	else {
 		/* connect() already succeeded, which is quite usual for unix
-		 * sockets. Let's avoid a second connect() probe to complete it,
-		 * but we need to ensure we'll wake up if there's no more handshake
-		 * pending (eg: for health checks).
+		 * sockets. Let's avoid a second connect() probe to complete it.
 		 */
 		conn->flags &= ~CO_FL_WAIT_L4_CONN;
-		if (!(conn->flags & CO_FL_HANDSHAKE))
-			data = 1;
 	}
 
 	conn->flags |= CO_FL_ADDR_TO_SET;
@@ -550,8 +546,6 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
 
 	conn_ctrl_init(conn);       /* registers the FD */
 	fdtab[fd].linger_risk = 0;  /* no need to disable lingering */
-	if (conn->flags & CO_FL_HANDSHAKE)
-		conn_sock_want_send(conn);  /* for connect status or proxy protocol */
 
 	if (conn_xprt_init(conn) < 0) {
 		conn_force_close(conn);
@@ -559,6 +553,17 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
 		return SF_ERR_RESOURCE;
 	}
 
+	if (conn->flags & (CO_FL_HANDSHAKE | CO_FL_WAIT_L4_CONN)) {
+		conn_sock_want_send(conn);  /* for connect status, proxy protocol or SSL */
+	}
+	else {
+		/* If there's no more handshake, we need to notify the data
+		 * layer when the connection is already OK otherwise we'll have
+		 * no other opportunity to do it later (eg: health checks).
+		 */
+		data = 1;
+	}
+
 	if (data)
 		conn_data_want_send(conn);  /* prepare to send data if any */
 
diff --git a/src/proxy.c b/src/proxy.c
index fec25555e8c3..a84a08fee23f 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -1156,7 +1156,7 @@ int stream_set_backend(struct stream *s, struct proxy *be)
 	 * be more reliable to store the list of analysers that have been run,
 	 * but what we do here is OK for now.
 	 */
-	s->req.analysers |= be->be_req_ana & (strm_li(s) ? ~strm_li(s)->analysers : 0);
+	s->req.analysers |= be->be_req_ana & ~(strm_li(s) ? strm_li(s)->analysers : 0);
 
 	/* If the target backend requires HTTP processing, we have to allocate
 	 * the HTTP transaction and hdr_idx if we did not have one.

--- End Message ---
--- Begin Message ---
Unblocked haproxy.

--- End Message ---

Reply to: