MEDIUM: backend: add the "http-reuse aggressive" strategy

This strategy is less extreme than "always", it only dispatches first
requests to validated reused connections, and moves a connection from
the idle list to the safe list once it has seen a second request, thus
proving that it could be reused.
diff --git a/src/backend.c b/src/backend.c
index 18f688d..9e8e9b6 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1046,17 +1046,43 @@
 			 */
 		}
 
-		if (((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS ||
-		     ((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_SAFE && s->txn && (s->txn->flags & TX_NOT_FIRST)))
-		    && !LIST_ISEMPTY(&srv->idle_conns)) {
-			/* We're going to have to pick the first connection
-			 * from this pool and use it for our purposes. We may
-			 * have to get rid of the current idle connection, so
-			 * for this we try to swap it with the other owner's.
-			 * That way it may remain alive for others to pick.
-			 */
+		/* Below we pick connections from the safe or idle lists based
+		 * on the strategy, the fact that this is a first or second
+		 * (retryable) request, with the indicated priority (1 or 2) :
+		 *
+		 *          SAFE                 AGGR                ALWS
+		 *
+		 *      +-----+-----+        +-----+-----+       +-----+-----+
+		 *   req| 1st | 2nd |     req| 1st | 2nd |    req| 1st | 2nd |
+		 *  ----+-----+-----+    ----+-----+-----+   ----+-----+-----+
+		 *  safe|  -  |  2  |    safe|  1  |  2  |   safe|  1  |  2  |
+		 *  ----+-----+-----+    ----+-----+-----+   ----+-----+-----+
+		 *  idle|  -  |  1  |    idle|  -  |  1  |   idle|  2  |  1  |
+		 *  ----+-----+-----+    ----+-----+-----+   ----+-----+-----+
+		 */
+
+		if (!LIST_ISEMPTY(&srv->idle_conns) &&
+		    ((s->be->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR &&
+		     s->txn && (s->txn->flags & TX_NOT_FIRST))) {
 			srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list);
+		}
+		else if (!LIST_ISEMPTY(&srv->safe_conns) &&
+			 ((s->txn && (s->txn->flags & TX_NOT_FIRST)) ||
+			  (s->be->options & PR_O_REUSE_MASK) >= PR_O_REUSE_AGGR)) {
+			srv_conn = LIST_ELEM(srv->safe_conns.n, struct connection *, list);
+		}
+		else if (!LIST_ISEMPTY(&srv->idle_conns) &&
+			 (s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS) {
+			srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list);
+		}
 
+		/* If we've picked a connection from the pool, we now have to
+		 * detach it. We may have to get rid of the previous idle
+		 * connection we had, so for this we try to swap it with the
+		 * other owner's. That way it may remain alive for others to
+		 * pick.
+		 */
+		if (srv_conn) {
 			LIST_DEL(&srv_conn->list);
 			LIST_INIT(&srv_conn->list);
 
@@ -1069,8 +1095,8 @@
 			reuse = 1;
 		}
 
+		/* we may have to release our connection if we couldn't swap it */
 		if (old_conn && !old_conn->owner) {
-			/* we couldn't swap our connection, let's release it */
 			LIST_DEL(&old_conn->list);
 			conn_force_close(old_conn);
 			conn_free(old_conn);
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 9f7a6b5..08adccd 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -5042,6 +5042,12 @@
 			if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
 				goto out;
 		}
+		else if (strcmp(args[1], "aggressive") == 0) {
+			curproxy->options &= ~PR_O_REUSE_MASK;
+			curproxy->options |= PR_O_REUSE_AGGR;
+			if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
+				goto out;
+		}
 		else if (strcmp(args[1], "always") == 0) {
 			/* enable a graceful server shutdown on an HTTP 404 response */
 			curproxy->options &= ~PR_O_REUSE_MASK;
@@ -5050,7 +5056,7 @@
 				goto out;
 		}
 		else {
-			Alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'always'.\n", file, linenum, args[0]);
+			Alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
diff --git a/src/proto_http.c b/src/proto_http.c
index 02ff485..c7ed011 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -5032,6 +5032,7 @@
 	struct proxy *fe = strm_fe(s);
 	struct connection *srv_conn;
 	struct server *srv;
+	unsigned int prev_flags = s->txn->flags;
 
 	/* FIXME: We need a more portable way of releasing a backend's and a
 	 * server's connections. We need a safer way to reinitialize buffer
@@ -5194,6 +5195,12 @@
 		else if ((srv_conn->flags & CO_FL_PRIVATE) ||
 			 ((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_NEVR))
 			si_idle_conn(&s->si[1], &srv->priv_conns);
+		else if (prev_flags & TX_NOT_FIRST)
+			/* note: we check the request, not the connection, but
+			 * this is valid for strategies SAFE and AGGR, and in
+			 * case of ALWS, we don't care anyway.
+			 */
+			si_idle_conn(&s->si[1], &srv->safe_conns);
 		else
 			si_idle_conn(&s->si[1], &srv->idle_conns);
 	}