[MEDIUM] config: remove the limitation of 10 reqadd/rspadd statements

Now we use a linked list, there is no limit anymore.
diff --git a/include/common/defaults.h b/include/common/defaults.h
index cada729..9b8d806 100644
--- a/include/common/defaults.h
+++ b/include/common/defaults.h
@@ -1,23 +1,23 @@
 /*
-  include/common/defaults.h
-  Miscellaneous default values.
-
-  Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
-
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Lesser General Public
-  License as published by the Free Software Foundation, version 2.1
-  exclusively.
-
-  This library is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+ * include/common/defaults.h
+ * Miscellaneous default values.
+ *
+ * Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 #ifndef _COMMON_DEFAULTS_H
 #define _COMMON_DEFAULTS_H
@@ -57,9 +57,6 @@
 // max # args on a stats socket
 #define MAX_STATS_ARGS  16
 
-// max # of added headers per request
-#define MAX_NEWHDR      10
-
 // max # of matches per regexp
 #define	MAX_MATCH       10
 
diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
index 7d16b5e..fa0537c 100644
--- a/include/common/mini-clist.h
+++ b/include/common/mini-clist.h
@@ -1,6 +1,6 @@
 /*
  * list.h : list manipulation macros and structures.
- * Copyright 2002-2008 Willy Tarreau <w@1wt.eu>
+ * Copyright 2002-2010 Willy Tarreau <w@1wt.eu>
  *
  */
 
@@ -33,6 +33,12 @@
 	struct list *ref; /* pointer to the target's list entry */
 };
 
+/* a word list is a generic list with a pointer to a string in each element. */
+struct wordlist {
+	struct list list;
+	char *s;
+};
+
 /* First undefine some macros which happen to also be defined on OpenBSD,
  * in sys/queue.h, used by sys/event.h
  */
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 54190ee..6130cf5 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -2,7 +2,7 @@
  * include/types/proxy.h
  * This file defines everything related to proxies.
  *
- * Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
+ * Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -240,7 +240,6 @@
 	int minlvl1, minlvl2;			/* minimum log level for each server, 0 by default */
 	int to_log;				/* things to be logged (LW_*) */
 	int stop_time;                          /* date to stop listening, when stopping != 0 (int ticks) */
-	int nb_reqadd, nb_rspadd;
 	struct hdr_exp *req_exp;		/* regular expressions for request headers */
 	struct hdr_exp *rsp_exp;		/* regular expressions for response headers */
 	int nb_req_cap, nb_rsp_cap;		/* # of headers to be captured */
@@ -249,7 +248,7 @@
 	struct pool_head *req_cap_pool,		/* pools of pre-allocated char ** used to build the sessions */
 	                 *rsp_cap_pool;
 	struct pool_head *hdr_idx_pool;         /* pools of pre-allocated int* used for headers indexing */
-	char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
+	struct list req_add, rsp_add;           /* headers to be added */
 	struct pxcounters counters;		/* statistics counters */
 	int grace;				/* grace time after stop request */
 	char *check_req;			/* HTTP or SSL request to use for PR_O_HTTP_CHK|PR_O_SSL3_CHK */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 75ae188..10013fe 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1,7 +1,7 @@
 /*
  * Configuration parser
  *
- * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -327,7 +327,7 @@
  */
 int warnif_rule_after_reqadd(struct proxy *proxy, const char *file, int line, char *arg)
 {
-	if (proxy->nb_reqadd) {
+	if (!LIST_ISEMPTY(&proxy->req_add)) {
 		Warning("parsing [%s:%d] : a '%s' rule placed after a 'reqadd' rule will still be processed before.\n",
 			file, line, arg);
 		return 1;
@@ -796,6 +796,8 @@
 	LIST_INIT(&p->mon_fail_cond);
 	LIST_INIT(&p->switching_rules);
 	LIST_INIT(&p->tcp_req.inspect_rules);
+	LIST_INIT(&p->req_add);
+	LIST_INIT(&p->rsp_add);
 
 	/* Timeouts are defined as -1 */
 	proxy_reset_timeouts(p);
@@ -3592,6 +3594,8 @@
 		warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
 	}
 	else if (!strcmp(args[0], "reqadd")) {  /* add request header */
+		struct wordlist *wl;
+
 		if (curproxy == &defproxy) {
 			Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
@@ -3600,19 +3604,15 @@
 		else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
 			err_code |= ERR_WARN;
 
-		if (curproxy->nb_reqadd >= MAX_NEWHDR) {
-			Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
-			err_code |= ERR_ALERT | ERR_FATAL;
-			goto out;
-		}
-	
 		if (*(args[1]) == 0) {
 			Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
-	
-		curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
+
+		wl = calloc(1, sizeof(*wl));
+		wl->s = strdup(args[1]);
+		LIST_ADDQ(&curproxy->req_add, &wl->list);
 		warnif_misplaced_reqadd(curproxy, file, linenum, args[0]);
 	}
 	else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) {  /* replace response header from a regex */
@@ -3800,6 +3800,8 @@
 		}
 	}
 	else if (!strcmp(args[0], "rspadd")) {  /* add response header */
+		struct wordlist *wl;
+
 		if (curproxy == &defproxy) {
 			Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
@@ -3808,19 +3810,15 @@
 		else if (warnifnotcap(curproxy, PR_CAP_RS, file, linenum, args[0], NULL))
 			err_code |= ERR_WARN;
 
-		if (curproxy->nb_rspadd >= MAX_NEWHDR) {
-			Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
-			err_code |= ERR_ALERT | ERR_FATAL;
-			goto out;
-		}
-	
 		if (*(args[1]) == 0) {
 			Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
 	
-		curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
+		wl = calloc(1, sizeof(*wl));
+		wl->s = strdup(args[1]);
+		LIST_ADDQ(&curproxy->rsp_add, &wl->list);
 	}
 	else if (!strcmp(args[0], "errorloc") ||
 		 !strcmp(args[0], "errorloc302") ||
diff --git a/src/haproxy.c b/src/haproxy.c
index 48f23d6..d645ee0 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1,6 +1,6 @@
 /*
  * HA-Proxy : High Availability-enabled HTTP/TCP proxy
- * Copyright 2000-2009  Willy Tarreau <w@1wt.eu>.
+ * Copyright 2000-2010  Willy Tarreau <w@1wt.eu>.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -23,15 +23,6 @@
  *
  * ChangeLog has moved to the CHANGELOG file.
  *
- * TODO:
- *   - handle properly intermediate incomplete server headers. Done ?
- *   - handle hot-reconfiguration
- *   - fix client/server state transition when server is in connect or headers state
- *     and client suddenly disconnects. The server *should* switch to SHUT_WR, but
- *     still handle HTTP headers.
- *   - remove MAX_NEWHDR
- *   - cut this huge file into several ones
- *
  */
 
 #include <stdio.h>
@@ -706,6 +697,7 @@
 	struct acl *acl, *aclb;
 	struct switching_rule *rule, *ruleb;
 	struct redirect_rule *rdr, *rdrb;
+	struct wordlist *wl, *wlb;
 	struct uri_auth *uap, *ua = NULL;
 	struct user_auth *user;
 	int i;
@@ -722,11 +714,17 @@
 		for (i = 0; i < HTTP_ERR_SIZE; i++)
 			chunk_destroy(&p->errmsg[i]);
 
-		for (i = 0; i < p->nb_reqadd; i++)
-			free(p->req_add[i]);
+		list_for_each_entry_safe(wl, wlb, &p->req_add, list) {
+			LIST_DEL(&wl->list);
+			free(wl->s);
+			free(wl);
+		}
 
-		for (i = 0; i < p->nb_rspadd; i++)
-			free(p->rsp_add[i]);
+		list_for_each_entry_safe(wl, wlb, &p->rsp_add, list) {
+			LIST_DEL(&wl->list);
+			free(wl->s);
+			free(wl);
+		}
 
 		list_for_each_entry_safe(cond, condb, &p->block_cond, list) {
 			LIST_DEL(&cond->list);
diff --git a/src/proto_http.c b/src/proto_http.c
index 5d70000..66024a7 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -1,7 +1,7 @@
 /*
  * HTTP protocol analyzer
  *
- * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -2515,6 +2515,7 @@
 	struct http_msg *msg = &txn->req;
 	struct acl_cond *cond;
 	struct redirect_rule *rule;
+	struct wordlist *wl;
 	int cur_idx;
 
 	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
@@ -2674,11 +2675,8 @@
 	} /* if must close keep-alive */
 
 	/* add request headers from the rule sets in the same order */
-	for (cur_idx = 0; cur_idx < px->nb_reqadd; cur_idx++) {
-		if (unlikely(http_header_add_tail(req,
-						  &txn->req,
-						  &txn->hdr_idx,
-						  px->req_add[cur_idx]) < 0))
+	list_for_each_entry(wl, &px->req_add, list) {
+		if (unlikely(http_header_add_tail(req, &txn->req, &txn->hdr_idx, wl->s) < 0))
 			goto return_bad_req;
 	}
 
@@ -4015,7 +4013,7 @@
 	struct http_txn *txn = &t->txn;
 	struct http_msg *msg = &txn->rsp;
 	struct proxy *cur_proxy;
-	int cur_idx;
+	struct wordlist *wl;
 	int conn_ka = 0, conn_cl = 0;
 	int must_close = 0;
 	int must_del_close = 0, must_keep = 0;
@@ -4228,11 +4226,10 @@
 			}
 
 			/* add response headers from the rule sets in the same order */
-			for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
+			list_for_each_entry(wl, &rule_set->rsp_add, list) {
 				if (txn->status < 200)
 					break;
-				if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
-								  rule_set->rsp_add[cur_idx]) < 0))
+				if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx, wl->s) < 0))
 					goto return_bad_resp;
 			}