[MEDIUM] errorloc now checked first from backend then from frontend

It is now possible to define an errorloc in the backend as well as
in the frontend. The backend's will be used first, and if undefined,
then the frontend's will be used instead. If none is used, then the
original error messages will be used.
diff --git a/include/proto/httperr.h b/include/proto/httperr.h
index 24a0cd1..749e427 100644
--- a/include/proto/httperr.h
+++ b/include/proto/httperr.h
@@ -25,12 +25,14 @@
 #include <types/httperr.h>
 
 extern const int http_err_codes[HTTP_ERR_SIZE];
-extern const char *http_err_msgs[HTTP_ERR_SIZE];
+extern struct chunk http_err_chunks[HTTP_ERR_SIZE];
 extern const char *HTTP_200;
 extern const char *HTTP_302;
 extern const char *HTTP_303;
 extern const char *HTTP_401_fmt;
 
+struct chunk *error_message(struct session *s, int msgnum);
+
 #endif /* _PROTO_HTTPERR_H */
 
 /*
diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h
index 5ee3a53..82f68a1 100644
--- a/include/proto/proto_http.h
+++ b/include/proto/proto_http.h
@@ -51,6 +51,7 @@
 void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_exp *exp);
 void manage_client_side_cookies(struct session *t, struct buffer *req);
 int stats_check_uri_auth(struct session *t, struct proxy *backend);
+void init_proto_http();
 
 #endif /* _PROTO_PROTO_HTTP_H */
 
diff --git a/src/backend.c b/src/backend.c
index f794ea5..f7dd675 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -30,6 +30,7 @@
 
 #include <proto/backend.h>
 #include <proto/fd.h>
+#include <proto/httperr.h>
 #include <proto/log.h>
 #include <proto/proto_http.h>
 #include <proto/queue.h>
@@ -545,7 +546,7 @@
 		/* if not retryable anymore, let's abort */
 		tv_eternity(&t->req->cex);
 		srv_close_with_err(t, conn_err, SN_FINST_C,
-				   503, &t->fe->errmsg[HTTP_ERR_503]);
+				   503, error_message(t, HTTP_ERR_503));
 		if (t->srv)
 			t->srv->failed_conns++;
 		t->be->beprm->failed_conns++;
@@ -587,7 +588,7 @@
 		case SN_ERR_INTERNAL:
 			tv_eternity(&t->req->cex);
 			srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
-					   500, &t->fe->errmsg[HTTP_ERR_500]);
+					   500, error_message(t, HTTP_ERR_500));
 			if (t->srv)
 				t->srv->failed_conns++;
 			t->be->beprm->failed_conns++;
@@ -647,7 +648,7 @@
 		/* note: it is guaranteed that t->srv == NULL here */
 		tv_eternity(&t->req->cex);
 		srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
-				   503, &t->fe->errmsg[HTTP_ERR_503]);
+				   503, error_message(t, HTTP_ERR_503));
 		if (t->srv)
 			t->srv->failed_conns++;
 		t->be->beprm->failed_conns++;
@@ -669,7 +670,7 @@
 	default:
 		tv_eternity(&t->req->cex);
 		srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
-				   500, &t->fe->errmsg[HTTP_ERR_500]);
+				   500, error_message(t, HTTP_ERR_500));
 		if (t->srv)
 			t->srv->failed_conns++;
 		t->be->beprm->failed_conns++;
diff --git a/src/cfgparse.c b/src/cfgparse.c
index f3659f5..d707685 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1740,7 +1740,7 @@
 	char *args[MAX_LINE_ARGS];
 	int arg;
 	int cfgerr = 0;
-	int nbchk, mininter, rc;
+	int nbchk, mininter;
 	int confsect = CFG_NONE;
 
 	struct proxy *curproxy = NULL;
@@ -2029,17 +2029,6 @@
 		if (curproxy->options & PR_O_LOGASAP)
 			curproxy->to_log &= ~LW_BYTES;
 
-		for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
-			if (!http_err_msgs[rc]) {
-				Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n");
-				abort();
-			}
-			if (!curproxy->errmsg[rc].str) {
-				curproxy->errmsg[rc].str = strdup(http_err_msgs[rc]);
-				curproxy->errmsg[rc].len = strlen(http_err_msgs[rc]);
-			}
-		}
-
 		/*
 		 * If this server supports a maxconn parameter, it needs a dedicated
 		 * tasks to fill the emptied slots when a connection leaves.
diff --git a/src/haproxy.c b/src/haproxy.c
index d2b6d10..0471364 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -83,6 +83,7 @@
 #include <proto/fd.h>
 #include <proto/log.h>
 #include <proto/polling.h>
+#include <proto/proto_http.h>
 #include <proto/proxy.h>
 #include <proto/queue.h>
 #include <proto/server.h>
@@ -353,6 +354,7 @@
 	start_date = now;
 
 	init_log();
+	init_proto_http();
 
 	cfg_polling_mechanism = POLL_USE_SELECT;  /* select() is always available */
 #if defined(ENABLE_POLL)
diff --git a/src/proto_http.c b/src/proto_http.c
index 89b5b60..83fb1da 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -114,9 +114,9 @@
 	[HTTP_ERR_504] = 504,
 };
 
-const char *http_err_msgs[HTTP_ERR_SIZE] = {
+static const char *http_err_msgs[HTTP_ERR_SIZE] = {
 	[HTTP_ERR_400] =
- 	"HTTP/1.0 400 Bad request\r\n"
+	"HTTP/1.0 400 Bad request\r\n"
 	"Cache-Control: no-cache\r\n"
 	"Connection: close\r\n"
 	"Content-Type: text/html\r\n"
@@ -173,6 +173,24 @@
 
 };
 
+/* We must put the messages here since GCC cannot initialize consts depending
+ * on strlen().
+ */
+struct chunk http_err_chunks[HTTP_ERR_SIZE];
+
+void init_proto_http()
+{
+	int msg;
+	for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
+		if (!http_err_msgs[msg]) {
+			Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
+			abort();
+		}
+
+		http_err_chunks[msg].str = (char *)http_err_msgs[msg];
+		http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
+	}
+}
 
 /*
  * We have 26 list of methods (1 per first letter), each of which can have
@@ -275,6 +293,19 @@
 		t->flags |= finst;
 }
 
+/* This function returns the appropriate error location for the given session
+ * and message.
+ */
+
+struct chunk *error_message(struct session *s, int msgnum)
+{
+	if (s->be->beprm->errmsg[msgnum].str)
+		return &s->be->beprm->errmsg[msgnum];
+	else if (s->fe->errmsg[msgnum].str)
+		return &s->fe->errmsg[msgnum];
+	else
+		return &http_err_chunks[msgnum];
+}
 
 /*
  * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
@@ -907,7 +938,7 @@
 			else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
 				/* read timeout : give up with an error message. */
 				t->logs.status = 408;
-				client_retnclose(t, &t->fe->errmsg[HTTP_ERR_408]);
+				client_retnclose(t, error_message(t, HTTP_ERR_408));
 				if (!(t->flags & SN_ERR_MASK))
 					t->flags |= SN_ERR_CLITO;
 				if (!(t->flags & SN_FINST_MASK))
@@ -1030,7 +1061,7 @@
 				t->logs.status = 403;
 				/* let's log the request time */
 				t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
-				client_retnclose(t, &t->fe->errmsg[HTTP_ERR_403]);
+				client_retnclose(t, error_message(t, HTTP_ERR_403));
 				goto return_prx_cond;
 			}
 
@@ -1233,7 +1264,7 @@
 	return_bad_req: /* let's centralize all bad requests */
 		t->hreq.hdr_state = HTTP_PA_ERROR;
 		t->logs.status = 400;
-		client_retnclose(t, &t->fe->errmsg[HTTP_ERR_400]);
+		client_retnclose(t, error_message(t, HTTP_ERR_400));
 	return_prx_cond:
 		if (!(t->flags & SN_ERR_MASK))
 			t->flags |= SN_ERR_PRXCOND;
@@ -1586,7 +1617,7 @@
 				tv_eternity(&req->cex);
 				t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
 				srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
-						   500, &t->fe->errmsg[HTTP_ERR_500]);
+						   500, error_message(t, HTTP_ERR_500));
 				return 1;
 			}
 
@@ -1603,7 +1634,7 @@
 					tv_eternity(&req->cex);
 					t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
 					srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
-							   503, &t->fe->errmsg[HTTP_ERR_503]);
+							   503, error_message(t, HTTP_ERR_503));
 					if (t->srv)
 						t->srv->failed_conns++;
 					t->fe->failed_conns++;
@@ -1788,7 +1819,7 @@
 						t->be->failed_secu++;
 						t->srv_state = SV_STCLOSE;
 						t->logs.status = 502;
-						client_return(t, &t->fe->errmsg[HTTP_ERR_502]);
+						client_return(t, error_message(t, HTTP_ERR_502));
 						if (!(t->flags & SN_ERR_MASK))
 							t->flags |= SN_ERR_PRXCOND;
 						if (!(t->flags & SN_FINST_MASK))
@@ -1819,7 +1850,7 @@
 					t->be->failed_secu++;
 					t->srv_state = SV_STCLOSE;
 					t->logs.status = 502;
-					client_return(t, &t->fe->errmsg[HTTP_ERR_502]);
+					client_return(t, error_message(t, HTTP_ERR_502));
 					if (!(t->flags & SN_ERR_MASK))
 						t->flags |= SN_ERR_PRXCOND;
 					if (!(t->flags & SN_FINST_MASK))
@@ -2259,7 +2290,7 @@
 
 			t->srv_state = SV_STCLOSE;
 			t->logs.status = 502;
-			client_return(t, &t->fe->errmsg[HTTP_ERR_502]);
+			client_return(t, error_message(t, HTTP_ERR_502));
 			if (!(t->flags & SN_ERR_MASK))
 				t->flags |= SN_ERR_SRVCL;
 			if (!(t->flags & SN_FINST_MASK))
@@ -2297,7 +2328,7 @@
 			t->be->failed_resp++;
 			t->srv_state = SV_STCLOSE;
 			t->logs.status = 504;
-			client_return(t, &t->fe->errmsg[HTTP_ERR_504]);
+			client_return(t, error_message(t, HTTP_ERR_504));
 			if (!(t->flags & SN_ERR_MASK))
 				t->flags |= SN_ERR_SRVTO;
 			if (!(t->flags & SN_FINST_MASK))
@@ -3070,7 +3101,7 @@
 	else {
 		/* unknown data source */
 		s->logs.status = 500;
-		client_retnclose(s, &s->fe->errmsg[HTTP_ERR_500]);
+		client_retnclose(s, error_message(s, HTTP_ERR_500));
 		if (!(s->flags & SN_ERR_MASK))
 			s->flags |= SN_ERR_PRXCOND;
 		if (!(s->flags & SN_FINST_MASK))