[MEDIUM] http: restore the original behaviour of option httpclose

Historically, "option httpclose" has always worked the same way. It
only mangles the "Connection" header in the request and the response
if needed, but does not affect the connection by itself, and ignores
any further data. It is dangerous to change this behaviour without
leaving any other alternative. If an active close is desired, it's
better to make use of "option forceclose" which does exactly what
it intends to do.

So as of now, "option httpclose" will only mangle the headers as
before, and will only affect the connection by itself when combined
with another connection-related option (eg: keepalive or server-close).
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 0fa2002..46787e5 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -2396,7 +2396,10 @@
 
   When this happens, it is possible to use "option forceclose". It will
   actively close the outgoing server channel as soon as the server has finished
-  to respond. This option implicitly enables the "httpclose" option.
+  to respond. This option implicitly enables the "httpclose" option. Note that
+  this option also enables the parsing of the full request and response, which
+  means we can close the connection to the server very quickly, releasing some
+  resources earlier than with httpclose.
 
   If this option has been enabled in a "defaults" section, it can be disabled
   in a specific instance by prepending the "no" keyword before it.
@@ -2535,8 +2538,9 @@
 
   This option may be set both in a frontend and in a backend. It is enabled if
   at least one of the frontend or backend holding a connection has it enabled.
-  It is worth noting that "option forceclose" has precedence over "httpclose",
-  which itself has precedence over "option http-server-close".
+  It is worth noting that "option forceclose" has precedence over "option
+  http-server-close" and that combining "http-server-close" with "httpclose"
+  basically achieve the same result as "forceclose".
 
   If this option has been enabled in a "defaults" section, it can be disabled
   in a specific instance by prepending the "no" keyword before it.
@@ -2562,14 +2566,18 @@
   be removed.
 
   It seldom happens that some servers incorrectly ignore this header and do not
-  close the connection eventough they reply "Connection: close". For this
-  reason, they are not compatible with older HTTP 1.0 browsers. If this
-  happens it is possible to use the "option forceclose" which actively closes
-  the request connection once the server responds.
+  close the connection eventhough they reply "Connection: close". For this
+  reason, they are not compatible with older HTTP 1.0 browsers. If this happens
+  it is possible to use the "option forceclose" which actively closes the
+  request connection once the server responds. Option "forceclose" also
+  releases the server connection earlier because it does not have to wait for
+  the client to acknowledge it.
 
   This option may be set both in a frontend and in a backend. It is enabled if
   at least one of the frontend or backend holding a connection has it enabled.
   If "option forceclose" is specified too, it has precedence over "httpclose".
+  If "option http-server-close" is enabled at the same time as "httpclose", it
+  basically achieves the same result as "option forceclose".
 
   If this option has been enabled in a "defaults" section, it can be disabled
   in a specific instance by prepending the "no" keyword before it.
diff --git a/src/proto_http.c b/src/proto_http.c
index ae7288a..07e701d 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -1808,17 +1808,21 @@
 	 * it, so that it can be enforced later.
 	 */
 
-	if (txn->flags & TX_REQ_VER_11) {	/* HTTP/1.1 */
+	if (conn_cl && conn_ka) {
+		txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+	}
+	else if (txn->flags & TX_REQ_VER_11) {	/* HTTP/1.1 */
 		if (conn_cl) {
-			txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
-			if (!conn_ka)
-				txn->flags |= TX_REQ_CONN_CLO;
+			txn->flags |= TX_REQ_CONN_CLO;
+			if ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN)
+				txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
 		}
 	} else {	/* HTTP/1.0 */
-		if (!conn_ka)
-			txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO | TX_REQ_CONN_CLO;
-		else if (conn_cl)
-			txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+		if (!conn_ka) {
+			txn->flags |= TX_REQ_CONN_CLO;
+			if ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN)
+				txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+		}
 	}
 	txn->flags |= TX_CON_HDR_PARS;
 }
@@ -2616,6 +2620,9 @@
 
 	/* Until set to anything else, the connection mode is set as TUNNEL. It will
 	 * only change if both the request and the config reference something else.
+	 * Option httpclose by itself does not set a mode, it remains a tunnel mode
+	 * in which headers are mangled. However, if another mode is set, it will
+	 * affect it (eg: server-close/keep-alive + httpclose = close).
 	 */
 
 	if ((txn->meth != HTTP_METH_CONNECT) &&
@@ -2625,17 +2632,21 @@
 			tmp = TX_CON_WANT_KAL;
 		if ((s->fe->options|s->be->options) & PR_O_SERVER_CLO)
 			tmp = TX_CON_WANT_SCL;
-		if ((s->fe->options|s->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))
+		if ((s->fe->options|s->be->options) & PR_O_FORCE_CLO)
 			tmp = TX_CON_WANT_CLO;
 
-		if (!(txn->flags & TX_REQ_XFER_LEN))
-			tmp = TX_CON_WANT_CLO;
-
 		if (!(txn->flags & TX_CON_HDR_PARS))
 			http_req_parse_connection_header(txn);
 
 		if ((txn->flags & TX_CON_WANT_MSK) < tmp)
 			txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
+
+		if ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) {
+			if ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE)
+				txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+			if (!(txn->flags & TX_REQ_XFER_LEN))
+				txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+		}
 	}
 
 	/* We're really certain of the connection mode (tunnel, close, keep-alive)
@@ -2650,7 +2661,9 @@
 	 * Connection header exists. Note that a CONNECT method will not enter
 	 * here.
 	 */
-	if (!(txn->flags & TX_REQ_CONN_CLO) && ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL)) {
+	if (!(txn->flags & TX_REQ_CONN_CLO) &&
+	    ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL ||
+	     ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE))) {
 		char *cur_ptr, *cur_end, *cur_next;
 		int old_idx, delta, val;
 		int must_delete;
@@ -3070,7 +3083,9 @@
 	}
 
 	/* 11: add "Connection: close" if needed and not yet set. */
-	if (!(txn->flags & TX_REQ_CONN_CLO) && ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL)) {
+	if (!(txn->flags & TX_REQ_CONN_CLO) &&
+	    ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL ||
+	     ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE))) {
 		if (unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
 						   "Connection: close", 17) < 0))
 			goto return_bad_req;
@@ -3471,7 +3486,7 @@
 				buffer_shutw_now(buf);
 				buf->cons->flags |= SI_FL_NOLINGER;
 			}
-			else if ((s->fe->options | s->be->options) & PR_O_FORCE_CLO) {
+			else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
 				/* Option forceclose is set, let's enforce it now
 				 * that we're not expecting any new data to come.
 				 */
@@ -4322,9 +4337,9 @@
 	 */
 
 	if ((txn->meth != HTTP_METH_CONNECT) &&
-	    (txn->status >= 200) &&
-	    (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN &&
-	    !(txn->flags & TX_CON_HDR_PARS)) {
+	    (txn->status >= 200) && !(txn->flags & TX_CON_HDR_PARS) &&
+	    ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN ||
+	     ((t->fe->options|t->be->options) & PR_O_HTTP_CLOSE))) {
 		int may_keep = 0, may_close = 0; /* how it may be understood */
 		struct hdr_ctx ctx;
 
@@ -4364,19 +4379,19 @@
 		 * handled. We also explicitly state that we will close in
 		 * case of an ambiguous response having no content-length.
 		 */
-		if ((may_close &&
+		if ((may_close && ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) &&
 		     (may_keep || ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL))) ||
 		    !(txn->flags & TX_RES_XFER_LEN))
 			txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
 
 		/* Now we must adjust the response header :
-		 *  - set "close" if may_keep and WANT_CLO
+		 *  - set "close" if may_keep and (WANT_CLO | httpclose)
 		 *  - remove "close" if WANT_SCL and REQ_1.1 and may_close and (content-length or TE_CHNK)
 		 *  - add "keep-alive" if WANT_SCL and REQ_1.0 and may_close and content-length
-		 *
-		 * Until we support the server-close mode, we'll only support the set "close".
 		 */
-		if (may_keep && (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO)
+		if (may_keep &&
+		    ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO ||
+		     ((t->fe->options|t->be->options) & PR_O_HTTP_CLOSE)))
 			must_close = 1;
 		else if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
 			 may_close && (txn->flags & TX_RES_XFER_LEN)) {