BUG/MINOR: fix option httplog validation with TCP frontends

Option httplog needs to be checked only once the proxy has been validated,
so that its final mode (tcp/http) can be used. Also we need to check for
httplog before checking the log format, so that we can report a warning
about this specific option and not about the format it implies.
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 622e168..15ed23a 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -344,6 +344,8 @@
 	int no_options;				/* PR_O_REDISP, PR_O_TRANSP, ... */
 	int no_options2;			/* PR_O2_* */
 
+	char *logformat_string;			/* log format string */
+	char *uniqueid_format_string;		/* unique-id format string */
 	struct {
 		const char *file;		/* file where the section appears */
 		int line;			/* line where the section appears */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 5bd2cfc..a45acb1 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1345,7 +1345,6 @@
 	int err_code = 0;
 	struct acl_cond *cond = NULL;
 	struct logsrv *tmplogsrv;
-	struct logformat_node *tmplf;
 	char *errmsg = NULL;
 
 	if (!strcmp(args[0], "listen"))
@@ -1564,21 +1563,17 @@
 			LIST_ADDQ(&curproxy->logsrvs, &node->list);
 		}
 
-		/* copy default log_format to curproxy */
-		list_for_each_entry(tmplf, &defproxy.logformat, list) {
-			struct logformat_node *node = malloc(sizeof(struct logformat_node));
-			memcpy(node, tmplf, sizeof(struct logformat_node));
-			LIST_INIT(&node->list);
-			LIST_ADDQ(&curproxy->logformat, &node->list);
-		}
+		/* get either a pointer to the logformat string or a copy of it */
+		curproxy->logformat_string = defproxy.logformat_string;
+		if (curproxy->logformat_string &&
+		    curproxy->logformat_string != default_http_log_format &&
+		    curproxy->logformat_string != default_tcp_log_format &&
+		    curproxy->logformat_string != clf_http_log_format)
+			curproxy->logformat_string = strdup(curproxy->logformat_string);
 
-		/* copy default unique_id to curproxy */
-		list_for_each_entry(tmplf, &defproxy.format_unique_id, list) {
-			struct logformat_node *node = malloc(sizeof(struct logformat_node));
-			memcpy(node, tmplf, sizeof(struct logformat_node));
-			LIST_INIT(&node->list);
-			LIST_ADDQ(&curproxy->format_unique_id, &node->list);
-		}
+		curproxy->uniqueid_format_string = defproxy.uniqueid_format_string;
+		if (curproxy->uniqueid_format_string)
+			curproxy->uniqueid_format_string = strdup(curproxy->uniqueid_format_string);
 
 		/* copy default header unique id */
 		if (defproxy.header_unique_id)
@@ -1614,6 +1609,13 @@
 		free(defproxy.expect_str);
 		if (defproxy.expect_regex) regfree(defproxy.expect_regex);
 
+		if (defproxy.logformat_string == default_http_log_format ||
+		    defproxy.logformat_string == default_tcp_log_format ||
+		    defproxy.logformat_string == clf_http_log_format)
+			free(defproxy.logformat_string);
+
+		free(defproxy.uniqueid_format_string);
+
 		for (rc = 0; rc < HTTP_ERR_SIZE; rc++)
 			chunk_destroy(&defproxy.errmsg[rc]);
 
@@ -3384,13 +3386,19 @@
 					goto out;
 				}
 			}
-			parse_logformat_string(logformat, curproxy, &curproxy->logformat, curproxy->mode);
+			if (curproxy->logformat_string != default_http_log_format &&
+			    curproxy->logformat_string != default_tcp_log_format &&
+			    curproxy->logformat_string != clf_http_log_format)
+				free(curproxy->logformat_string);
+			curproxy->logformat_string = logformat;
 		}
 		else if (!strcmp(args[1], "tcplog")) {
-			char *logformat;
 			/* generate a detailed TCP log */
-			logformat = default_tcp_log_format;
-			parse_logformat_string(logformat, curproxy, &curproxy->logformat, curproxy->mode);
+			if (curproxy->logformat_string != default_http_log_format &&
+			    curproxy->logformat_string != default_tcp_log_format &&
+			    curproxy->logformat_string != clf_http_log_format)
+				free(curproxy->logformat_string);
+			curproxy->logformat_string = default_tcp_log_format;
 		}
 		else if (!strcmp(args[1], "tcpka")) {
 			/* enable TCP keep-alives on client and server sessions */
@@ -4639,7 +4647,8 @@
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
-		parse_logformat_string(args[1], curproxy, &curproxy->format_unique_id, PR_MODE_HTTP);
+		free(curproxy->uniqueid_format_string);
+		curproxy->uniqueid_format_string = strdup(args[1]);
 	}
 
 	else if (strcmp(args[0], "unique-id-header") == 0) {
@@ -4658,7 +4667,12 @@
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
-		parse_logformat_string(args[1], curproxy, &curproxy->logformat, curproxy->mode);
+
+		if (curproxy->logformat_string != default_http_log_format &&
+		    curproxy->logformat_string != default_tcp_log_format &&
+		    curproxy->logformat_string != clf_http_log_format)
+			free(curproxy->logformat_string);
+		curproxy->logformat_string = strdup(args[1]);
 	}
 
 	else if (!strcmp(args[0], "log") && kwm == KWM_NO) {
@@ -6208,6 +6222,13 @@
 			}
 		}
 
+		/* compile the log format */
+		if (curproxy->logformat_string)
+			parse_logformat_string(curproxy->logformat_string, curproxy, &curproxy->logformat, curproxy->mode);
+
+		if (curproxy->uniqueid_format_string)
+			parse_logformat_string(curproxy->uniqueid_format_string, curproxy, &curproxy->format_unique_id, PR_MODE_HTTP);
+
 		/* first, we will invert the servers list order */
 		newsrv = NULL;
 		while (curproxy->srv) {
diff --git a/src/haproxy.c b/src/haproxy.c
index 8d3e6e3..ff962c2 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -831,6 +831,12 @@
 		free(p->capture_name);
 		free(p->monitor_uri);
 		free(p->rdp_cookie_name);
+		if (p->logformat_string == default_http_log_format ||
+		    p->logformat_string == default_tcp_log_format ||
+		    p->logformat_string == clf_http_log_format)
+			free(p->logformat_string);
+
+		free(p->uniqueid_format_string);
 
 		for (i = 0; i < HTTP_ERR_SIZE; i++)
 			chunk_destroy(&p->errmsg[i]);
diff --git a/src/proxy.c b/src/proxy.c
index bc5779f..3568251 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -406,6 +406,13 @@
 		Warning("config : 'option httplog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'.\n",
 			proxy_type_str(curproxy), curproxy->id);
 	}
+	if (curproxy->logformat_string == default_http_log_format ||
+	    curproxy->logformat_string == clf_http_log_format) {
+		curproxy->logformat_string = default_tcp_log_format;
+		Warning("config : 'option httplog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'.\n",
+			proxy_type_str(curproxy), curproxy->id);
+	}
+
 	return 0;
 }