OPTIM/MINOR: session: abort if possible before connecting to the backend

Depending on the path that led to sess_update_stream_int(), it's
possible that we had a read error on the frontend, but that we haven't
checked if we may abort the connection.

This was seen in particular the following setup: tcp mode, with
abortonclose set, frontend using ssl. If the ssl connection had a first
successful read, but the second read failed, we would stil try to open a
connection to the backend, although we had enough information to close
the connection early.

sess_update_stream_int() had some logic to handle that case in the
SI_ST_QUE and SI_ST_TAR, but that was missing in the SI_ST_ASS case.

This patches addresses the issue by verifying the state of the req
channel (and the abortonclose option) right before opening the
connection to the backend, so we have the opportunity to close the
connection there, and factorizes the shared SI_ST_{QUE,TAR,ASS} code.
diff --git a/src/stream.c b/src/stream.c
index b5cfcfd..f6e1dc4 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -774,6 +774,14 @@
 	req->wex = TICK_ETERNITY;
 }
 
+/* Check if the connection request is in such a state that it can be aborted. */
+static int check_req_may_abort(struct channel *req, struct stream *s)
+{
+	return ((req->flags & (CF_READ_ERROR)) ||
+	        ((req->flags & CF_SHUTW_NOW) &&  /* empty and client aborted */
+	         (channel_is_empty(req) || s->be->options & PR_O_ABRT_CLOSE)));
+}
+
 /* Update back stream interface status for input states SI_ST_ASS, SI_ST_QUE,
  * SI_ST_TAR. Other input states are simply ignored.
  * Possible output states are SI_ST_CLO, SI_ST_TAR, SI_ST_ASS, SI_ST_REQ, SI_ST_CON
@@ -798,6 +806,14 @@
 		/* Server assigned to connection request, we have to try to connect now */
 		int conn_err;
 
+		/* Before we try to initiate the connection, see if the
+		 * request may be aborted instead.
+		 */
+		if (check_req_may_abort(req, s)) {
+			si->err_type |= SI_ET_CONN_ABRT;
+			goto abort_connection;
+		}
+
 		conn_err = connect_server(s);
 		srv = objt_server(s->target);
 
@@ -893,19 +909,10 @@
 		}
 
 		/* Connection remains in queue, check if we have to abort it */
-		if ((req->flags & (CF_READ_ERROR)) ||
-		    ((req->flags & CF_SHUTW_NOW) &&   /* empty and client aborted */
-		     (channel_is_empty(req) || s->be->options & PR_O_ABRT_CLOSE))) {
-			/* give up */
-			si->exp = TICK_ETERNITY;
+		if (check_req_may_abort(req, s)) {
 			s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
-			si_shutr(si);
-			si_shutw(si);
 			si->err_type |= SI_ET_QUEUE_ABRT;
-			si->state = SI_ST_CLO;
-			if (s->srv_error)
-				s->srv_error(s, si);
-			return;
+			goto abort_connection;
 		}
 
 		/* Nothing changed */
@@ -913,18 +920,9 @@
 	}
 	else if (si->state == SI_ST_TAR) {
 		/* Connection request might be aborted */
-		if ((req->flags & (CF_READ_ERROR)) ||
-		    ((req->flags & CF_SHUTW_NOW) &&  /* empty and client aborted */
-		     (channel_is_empty(req) || s->be->options & PR_O_ABRT_CLOSE))) {
-			/* give up */
-			si->exp = TICK_ETERNITY;
-			si_shutr(si);
-			si_shutw(si);
+		if (check_req_may_abort(req, s)) {
 			si->err_type |= SI_ET_CONN_ABRT;
-			si->state = SI_ST_CLO;
-			if (s->srv_error)
-				s->srv_error(s, si);
-			return;
+			goto abort_connection;
 		}
 
 		if (!(si->flags & SI_FL_EXP))
@@ -942,6 +940,17 @@
 			si->state = SI_ST_REQ;
 		return;
 	}
+	return;
+
+abort_connection:
+	/* give up */
+	si->exp = TICK_ETERNITY;
+	si_shutr(si);
+	si_shutw(si);
+	si->state = SI_ST_CLO;
+	if (s->srv_error)
+		s->srv_error(s, si);
+	return;
 }
 
 /* Set correct stream termination flags in case no analyser has done it. It