[MEDIUM] http: add options to ignore invalid header names

Sometimes it is required to let invalid requests pass because
applications sometimes take time to be fixed and other servers
do not care. Thus we provide two new options :

     option accept-invalid-http-request  (for the frontend)
     option accept-invalid-http-response (for the backend)

When those options are set, invalid requests or responses do
not cause a 403/502 error to be generated.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index a0b8d63..3f86ce4 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -123,6 +123,8 @@
 	{ "splice-response", PR_O2_SPLIC_RTR, PR_CAP_FE|PR_CAP_BE, 0 },
 	{ "splice-auto",     PR_O2_SPLIC_AUT, PR_CAP_FE|PR_CAP_BE, 0 },
 #endif
+	{ "accept-invalid-http-request",  PR_O2_REQBUG_OK, PR_CAP_FE, 0 },
+	{ "accept-invalid-http-response", PR_O2_RSPBUG_OK, PR_CAP_BE, 0 },
 	{ NULL, 0, 0, 0 }
 };
 
diff --git a/src/client.c b/src/client.c
index 02c7c02..b3e1980 100644
--- a/src/client.c
+++ b/src/client.c
@@ -266,6 +266,9 @@
 			txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */
 			txn->req.sol = txn->req.eol = NULL;
 			txn->req.som = txn->req.eoh = 0; /* relative to the buffer */
+			txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */
+			if (p->options2 & PR_O2_REQBUG_OK)
+				txn->req.err_pos = -1; /* let buggy requests pass */
 			txn->auth_hdr.len = -1;
 
 			if (p->nb_req_cap > 0) {
diff --git a/src/proto_http.c b/src/proto_http.c
index 359488b..a77ab79 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -1375,7 +1375,14 @@
 			EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
 		}
 
-		goto http_msg_invalid;
+		if (likely(msg->err_pos < -1) || *ptr == '\n')
+			goto http_msg_invalid;
+
+		if (msg->err_pos == -1) /* capture error pointer */
+			msg->err_pos = ptr - buf->data; /* >= 0 now */
+
+		/* and we still accept this non-token character */
+		EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
 
 	http_msg_hdr_l1_sp:
 	case HTTP_MSG_HDR_L1_SP:
@@ -2055,6 +2062,8 @@
 					s->rep->rto = s->req->wto = s->be->timeout.server;
 					s->req->cto = s->be->timeout.connect;
 					s->conn_retries = s->be->conn_retries;
+					if (s->be->options2 & PR_O2_RSPBUG_OK)
+						s->txn.rsp.err_pos = -1; /* let buggy responses pass */
 					s->flags |= SN_BE_ASSIGNED;
 					break;
 				}
@@ -2076,6 +2085,8 @@
 			s->rep->rto = s->req->wto = s->be->timeout.server;
 			s->req->cto = s->be->timeout.connect;
 			s->conn_retries = s->be->conn_retries;
+			if (s->be->options2 & PR_O2_RSPBUG_OK)
+				s->txn.rsp.err_pos = -1; /* let buggy responses pass */
 			s->flags |= SN_BE_ASSIGNED;
 		}
 	} while (s->be != cur_proxy);  /* we loop only if s->be has changed */
@@ -3054,6 +3065,8 @@
 				t->rep->rto = t->req->wto = t->be->timeout.server;
 				t->req->cto = t->be->timeout.connect;
 				t->conn_retries = t->be->conn_retries;
+				if (t->be->options2 & PR_O2_RSPBUG_OK)
+					t->txn.rsp.err_pos = -1; /* let buggy responses pass */
 				last_hdr = 1;
 				break;
 
@@ -3175,6 +3188,8 @@
 			t->rep->rto = t->req->wto = t->be->timeout.server;
 			t->req->cto = t->be->timeout.connect;
 			t->conn_retries = t->be->conn_retries;
+			if (t->be->options2 & PR_O2_RSPBUG_OK)
+				t->txn.rsp.err_pos = -1; /* let buggy responses pass */
 			done = 1;
 			break;