On Thu, Jun 5, 2014 at 11:40 AM, Sasha Pachev <[email protected]> wrote:
> Thierry:
>
> Will try to get this done in the next day. I assume you want the docs
> as a patch to the documentation file, right?
>
> On Thu, Jun 5, 2014 at 7:15 AM, Thierry FOURNIER
> <[email protected]> wrote:
>> Willy have the last word :) The doc is missing. Can you do this ?

Attached is the patch including the documentation.

-- 
Sasha Pachev

Fast Running Blog.
http://fastrunningblog.com
Run. Blog. Improve. Repeat.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index cdac65c..94e9549 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -2866,6 +2866,8 @@ http-check send-state
 http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
               add-header <name> <fmt> | set-header <name> <fmt> |
               del-header <name> | set-nice <nice> | set-log-level <level> |
+              replace-header <name> <match-regex> <replace-fmt> |
+              modify-header <name> <match-regex> <replace-fmt> |
               set-tos <tos> | set-mark <mark> |
               add-acl(<file name>) <key fmt> |
               del-acl(<file name>) <key fmt> |
@@ -2933,6 +2935,34 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
     - "del-header" removes all HTTP header fields whose name is specified in
       <name>.
 
+    - "replace-header" matches the regular expression in the header value 
+      according to match-regex and replaces it with the replace-fmt argument.
+      Format characters are allowed in replace-fmt and work like in fmt 
+      arguments in add-header. The match is case-sensitive.
+
+      Example:
+
+        http-request replace-header Set-Cookie  (bar=bar.*) \1;id=%Ts:%pid
+
+    - "modify-header" works like "replace-header" except it matches and replaces
+      every part of the value delimited by ; instead of the entire header.
+      
+      Example:
+
+        http-response modify-header Set-Cookie  (bar=bar.*) \1;ip=%bi
+
+      This converts:
+
+        Set-Cookie: bar=barbarian; foo=foo; bar=barcode
+
+      into:
+
+        Set-Cookie: bar=barbarian;ip=192.168.1.20; foo=foo; bar=barcode;ip=\
+        192.168.1.20
+
+      assuming the backend IP is 192.168.1.20
+
+
     - "set-nice" sets the "nice" factor of the current request being processed.
       It only has effect against the other requests being processed at the same
       time. The default value is 0, unless altered by the "nice" setting on the
@@ -3057,6 +3087,8 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
 
 http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
                 set-header <name> <fmt> | del-header <name> |
+                replace-header <name> <regex-match> <replace-fmt> |
+                modify-header <name> <regex-match> <replace-fmt> |
                 set-log-level <level> | set-mark <mark> | set-tos <tos> |
                 add-acl(<file name>) <key fmt> |
                 del-acl(<file name>) <key fmt> |
@@ -3101,6 +3133,34 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
     - "del-header" removes all HTTP header fields whose name is specified in
       <name>.
 
+    - "replace-header" matches the regular expression in the header value 
+      according to match-regex and replaces it with the replace-fmt argument.
+      Format characters are allowed in replace-fmt and work like in fmt 
+      arguments in add-header. The match is case-sensitive. 
+
+      Example:
+
+        http-response replace-header Set-Cookie  (bar=bar.*) \1;id=%Ts:%pid
+
+    - "modify-header" works like "replace-header" except it matches and replaces
+      every part of the value delimited by ; instead of the entire header.
+
+      Example:
+
+        http-response modify-header Set-Cookie  (bar=bar.*) \1;ip=%bi
+
+      This converts:
+
+        Set-Cookie: bar=barbarian; foo=foo; bar=barcode
+
+      into:
+
+        Set-Cookie: bar=barbarian;ip=192.168.1.20; foo=foo; bar=barcode;ip=\
+        192.168.1.20
+
+      assuming the backend IP is 192.168.1.20
+
+
     - "set-nice" sets the "nice" factor of the current request being processed.
       It only has effect against the other requests being processed at the same
       time. The default value is 0, unless altered by the "nice" setting on the
diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h
index 6370e2d..e898ca8 100644
--- a/include/proto/proto_http.h
+++ b/include/proto/proto_http.h
@@ -116,6 +116,7 @@ void http_reset_txn(struct session *s);
 struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
 struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
 void free_http_req_rules(struct list *r);
+void free_http_res_rules(struct list *r);
 struct chunk *http_error_message(struct session *s, int msgnum);
 struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
                                                const char **args, char **errmsg, int use_fmt);
diff --git a/include/types/proto_http.h b/include/types/proto_http.h
index e1d04d6..d7d4430 100644
--- a/include/types/proto_http.h
+++ b/include/types/proto_http.h
@@ -247,6 +247,8 @@ enum {
 	HTTP_REQ_ACT_ADD_HDR,
 	HTTP_REQ_ACT_SET_HDR,
 	HTTP_REQ_ACT_DEL_HDR,
+	HTTP_REQ_ACT_REPLACE_HDR,
+	HTTP_REQ_ACT_MODIFY_HDR,
 	HTTP_REQ_ACT_REDIR,
 	HTTP_REQ_ACT_SET_NICE,
 	HTTP_REQ_ACT_SET_LOGL,
@@ -267,6 +269,8 @@ enum {
 	HTTP_RES_ACT_ALLOW,
 	HTTP_RES_ACT_DENY,
 	HTTP_RES_ACT_ADD_HDR,
+	HTTP_RES_ACT_MODIFY_HDR,
+	HTTP_RES_ACT_REPLACE_HDR,
 	HTTP_RES_ACT_SET_HDR,
 	HTTP_RES_ACT_DEL_HDR,
 	HTTP_RES_ACT_SET_NICE,
@@ -425,6 +429,7 @@ struct http_req_rule {
 			char *name;            /* header name */
 			int name_len;          /* header name's length */
 			struct list fmt;       /* log-format compatible expression */
+			regex_t* re;           /* used by replace-header and modify-header */
 		} hdr_add;                     /* args used by "add-header" and "set-header" */
 		struct redirect_rule *redir;   /* redirect rule or "http-request redirect" */
 		int nice;                      /* nice value for HTTP_REQ_ACT_SET_NICE */
@@ -450,6 +455,7 @@ struct http_res_rule {
 			char *name;            /* header name */
 			int name_len;          /* header name's length */
 			struct list fmt;       /* log-format compatible expression */
+			regex_t* re;           /* used by replace-header and modify-header */
 		} hdr_add;                     /* args used by "add-header" and "set-header" */
 		int nice;                      /* nice value for HTTP_RES_ACT_SET_NICE */
 		int loglevel;                  /* log-level value for HTTP_RES_ACT_SET_LOGL */
diff --git a/src/haproxy.c b/src/haproxy.c
index 77871b0..84e22e3 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1202,6 +1202,7 @@ void deinit(void)
 		free(p->fwdfor_hdr_name);
 
 		free_http_req_rules(&p->http_req_rules);
+		free_http_res_rules(&p->http_res_rules);
 		free(p->task);
 
 		pool_destroy2(p->req_cap_pool);
diff --git a/src/proto_http.c b/src/proto_http.c
index 30bd359..232d386 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -252,6 +252,9 @@ fd_set http_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set
 #error "Check if your OS uses bitfields for fd_sets"
 #endif
 
+#define ACTION_IS_REGFIX(rule,req_or_res) ((rule)->action == HTTP_##req_or_res##_ACT_MODIFY_HDR || \
+ 	(rule)->action == HTTP_##req_or_res##_ACT_REPLACE_HDR)
+
 static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *s, struct http_txn *txn);
 
 void init_proto_http()
@@ -3176,6 +3179,125 @@ static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
 #endif
 }
 
+static int http_regfix_replace(regex_t* re, char* dst, uint dst_size, char* val,
+	const char*  rep_str)
+{
+
+	if (regexec(re, val, MAX_MATCH, pmatch, 0)) 
+		return 0;
+
+	return exp_replace(dst, dst_size, val, rep_str, pmatch);
+}
+
+static int http_regfix_modify(regex_t* re, char* dst, uint dst_size, char* val, char delim,
+	const char*  rep_str)
+{
+	char* p = val;
+	char* dst_end = dst + dst_size;
+	char* dst_p = dst;
+
+	for (;;) {
+		char *p_delim;
+		const char* tok_end;
+
+		if ((p_delim = (char*)strchr(p, delim))) {
+			*p_delim = 0;
+			tok_end = p_delim;
+		} else {
+			tok_end = p + strlen(p);
+		}
+
+		if (regexec(re, p, MAX_MATCH, pmatch, 0) == 0) {
+			int replace_n = exp_replace(dst_p, dst_end - dst_p, p, rep_str, pmatch);
+
+			if (replace_n < 0)
+				return -1;
+
+			dst_p += replace_n;
+		}	else {
+			uint len = tok_end - p;
+
+			if (dst_p + len >= dst_end)
+				return -1;
+
+			memcpy(dst_p, p, len);
+			dst_p += len;
+		}
+
+		if (dst_p >= dst_end)
+			return -1;
+
+		if (p_delim) {
+			*p_delim = delim;
+			*dst_p++ = delim;
+			p = p_delim + 1;
+		} else {
+			*dst_p = 0;
+			break;
+		}
+	}
+
+	return dst_p - dst;
+}
+
+static int http_regfix_header(struct session* s, struct http_msg *msg, const char* name, uint name_len, 
+		char* buf, struct hdr_idx* idx, struct list *fmt, regex_t* re,
+		struct hdr_ctx* ctx, int action)
+{
+	ctx->idx = 0;
+
+	while (http_find_full_header2(name, name_len, buf, idx, ctx))
+  {
+  	struct hdr_idx_elem *hdr = idx->v + ctx->idx;
+  	int delta;
+  	char* val = (char*)ctx->line + name_len + 2;
+  	char* val_end = (char*)ctx->line + hdr->len;
+  	char save_val_end = *val_end;
+  	char* reg_dst_buf;
+  	uint reg_dst_buf_size;
+  	int n_replaced;
+
+  	*val_end = 0;
+		trash.len = build_logline(s, trash.str, trash.size, fmt);
+
+		if (trash.len >= trash.size - 1)
+			return -1;
+
+ 		reg_dst_buf = trash.str + trash.len + 1;
+ 		reg_dst_buf_size = trash.size - trash.len - 1;
+
+ 		switch (action)
+ 		{
+ 			case HTTP_REQ_ACT_MODIFY_HDR:
+ 			case HTTP_RES_ACT_MODIFY_HDR:
+ 				n_replaced = http_regfix_modify(re, reg_dst_buf, reg_dst_buf_size, val, ';', trash.str);
+ 				break;
+ 			case HTTP_REQ_ACT_REPLACE_HDR:
+ 			case HTTP_RES_ACT_REPLACE_HDR:
+ 				n_replaced = http_regfix_replace(re, reg_dst_buf, reg_dst_buf_size, val, trash.str);
+ 				break;
+ 			default: /* impossible */
+ 				return -1;
+ 		}
+
+		*val_end = save_val_end;
+ 		
+ 		if (n_replaced == 0)
+ 			continue;
+
+ 		if (n_replaced < 0) 
+ 			return -1;
+
+  	delta = buffer_replace2(msg->chn->buf, val, val_end,
+  	   reg_dst_buf, n_replaced);
+
+  	hdr->len += delta;
+  	http_msg_move_end(msg, delta);
+  }
+
+  return 0;
+}
+
 /* Executes the http-request rules <rules> for session <s>, proxy <px> and
  * transaction <txn>. Returns the verdict of the first rule that prevents
  * further processing of the request (auth, deny, ...), and defaults to
@@ -3265,6 +3387,14 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
 			s->logs.level = rule->arg.loglevel;
 			break;
 
+		case HTTP_REQ_ACT_REPLACE_HDR:
+		case HTTP_REQ_ACT_MODIFY_HDR:
+			if (http_regfix_header(s, &txn->req, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
+						 txn->req.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt, 
+						 rule->arg.hdr_add.re, &ctx, rule->action))
+				return HTTP_RULE_RES_ABRT;
+			break;
+
 		case HTTP_REQ_ACT_DEL_HDR:
 		case HTTP_REQ_ACT_SET_HDR:
 			ctx.idx = 0;
@@ -3446,6 +3576,14 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
 			s->logs.level = rule->arg.loglevel;
 			break;
 
+		case HTTP_RES_ACT_MODIFY_HDR:
+		case HTTP_RES_ACT_REPLACE_HDR:
+			if (http_regfix_header(s, &txn->rsp, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
+						 txn->rsp.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt,
+						 rule->arg.hdr_add.re, &ctx, rule->action))
+				return NULL;
+			break;
+		
 		case HTTP_RES_ACT_DEL_HDR:
 		case HTTP_RES_ACT_SET_HDR:
 			ctx.idx = 0;
@@ -8757,6 +8895,24 @@ void http_reset_txn(struct session *s)
 	s->rep->analyse_exp = TICK_ETERNITY;
 }
 
+static inline void free_regex(regex_t* re)
+{
+	if (re) {
+		regfree(re);
+		free(re);
+	}
+}
+
+void free_http_res_rules(struct list *r) {
+	struct http_res_rule *tr, *pr;
+
+	list_for_each_entry_safe(pr, tr, r, list) {
+		LIST_DEL(&pr->list);
+		free_regex(pr->arg.hdr_add.re); 
+		free(pr);
+	}
+}
+
 void free_http_req_rules(struct list *r) {
 	struct http_req_rule *tr, *pr;
 
@@ -8765,6 +8921,7 @@ void free_http_req_rules(struct list *r) {
 		if (pr->action == HTTP_REQ_ACT_AUTH)
 			free(pr->arg.auth.realm);
 
+		free_regex(pr->arg.hdr_add.re); 
 		free(pr);
 	}
 }
@@ -8775,6 +8932,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
 	struct http_req_rule *rule;
 	struct http_req_action_kw *custom = NULL;
 	int cur_arg;
+	int regfix_rule = 0;
 
 	rule = (struct http_req_rule*)calloc(1, sizeof(struct http_req_rule));
 	if (!rule) {
@@ -8884,12 +9042,33 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
 		else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0)
 			goto bad_log_level;
 		cur_arg++;
-	} else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
-		rule->action = *args[0] == 'a' ? HTTP_REQ_ACT_ADD_HDR : HTTP_REQ_ACT_SET_HDR;
+	} else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0 ||
+			strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "modify-header") == 0) {
+		const char* fmt_arg;
+
+		switch (*args[0])
+		{
+			case 'a':
+				rule->action = HTTP_REQ_ACT_ADD_HDR;
+				break;
+			case 's':
+				rule->action = HTTP_REQ_ACT_SET_HDR;
+				break;
+			case 'r':
+				rule->action = HTTP_REQ_ACT_REPLACE_HDR;
+				regfix_rule = 1;
+				break;
+			case 'm':
+				rule->action = HTTP_REQ_ACT_MODIFY_HDR;
+				regfix_rule = 1;
+				break;
+		}
+
 		cur_arg = 1;
 
 		if (!*args[cur_arg] || !*args[cur_arg+1] ||
-		    (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
+		    (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 
+		    	&& strcmp(args[cur_arg+2], "unless") != 0 && !ACTION_IS_REGFIX(rule,REQ))) {
 			Alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
 			      file, linenum, args[0]);
 			goto out_err;
@@ -8900,9 +9079,31 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
 		LIST_INIT(&rule->arg.hdr_add.fmt);
 
 		proxy->conf.args.ctx = ARGC_HRQ;
-		parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+		fmt_arg = (regfix_rule) ? args[cur_arg + 2] : args[cur_arg + 1];
+
+		if (regfix_rule && !*fmt_arg) {
+				Alert("parsing [%s:%d]: 'http-response %s' expects exactly 3 arguments.\n",
+			      file, linenum, args[0]);
+				goto out_err;
+		}
+
+		parse_logformat_string(fmt_arg, proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
 				       (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
 				       file, linenum);
+
+		if (regfix_rule) {
+			if (!(rule->arg.hdr_add.re = (regex_t*)calloc(1, sizeof(regex_t)))) {
+				Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
+				goto out_err;
+			}
+
+			if (regcomp(rule->arg.hdr_add.re, args[cur_arg + 1], REG_EXTENDED)) {
+				Alert("parsing [%s:%d] : '%s' : bad regular expression.\n", file, linenum, 
+					args[cur_arg + 1]);
+				goto out_err;
+			}
+		}
+
 		free(proxy->conf.lfs_file);
 		proxy->conf.lfs_file = strdup(proxy->conf.args.file);
 		proxy->conf.lfs_line = proxy->conf.args.line;
@@ -8912,7 +9113,8 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
 		cur_arg = 1;
 
 		if (!*args[cur_arg] ||
-		    (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
+		    (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && 
+		    	strcmp(args[cur_arg+1], "unless") != 0 && !regfix_rule)) {
 			Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
 			      file, linenum, args[0]);
 			goto out_err;
@@ -9090,7 +9292,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
 		}
 		rule->cond = cond;
 	}
-	else if (*args[cur_arg]) {
+	else if (*args[cur_arg] && !regfix_rule) {
 		Alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
 		      " either 'if' or 'unless' followed by a condition but found '%s'.\n",
 		      file, linenum, args[0], args[cur_arg]);
@@ -9109,6 +9311,7 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
 	struct http_res_rule *rule;
 	struct http_res_action_kw *custom = NULL;
 	int cur_arg;
+	int regfix_rule;
 
 	rule = calloc(1, sizeof(*rule));
 	if (!rule) {
@@ -9203,12 +9406,34 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
 		else if ((rule->arg.loglevel = get_log_level(args[cur_arg] + 1)) == 0)
 			goto bad_log_level;
 		cur_arg++;
-	} else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
-		rule->action = *args[0] == 'a' ? HTTP_RES_ACT_ADD_HDR : HTTP_RES_ACT_SET_HDR;
+	} else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0 || 
+		       strcmp(args[0], "replace-header") == 0 || 
+		       strcmp(args[0], "modify-header") == 0) {
+		const char* fmt_arg;
+
+		switch ((args[0])[0])
+		{
+			case 'a':
+				rule->action = HTTP_RES_ACT_ADD_HDR;
+				break;
+			case 's':
+				rule->action = HTTP_RES_ACT_SET_HDR;
+				break;
+			case 'r':
+				rule->action = HTTP_RES_ACT_REPLACE_HDR;
+				regfix_rule = 1;
+				break;
+			case 'm':
+				rule->action = HTTP_RES_ACT_MODIFY_HDR;
+				regfix_rule = 1;
+				break;
+		}
+
 		cur_arg = 1;
 
 		if (!*args[cur_arg] || !*args[cur_arg+1] ||
-		    (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
+		    (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && 
+		    	strcmp(args[cur_arg+2], "unless") != 0 && !regfix_rule)) {
 			Alert("parsing [%s:%d]: 'http-response %s' expects exactly 2 arguments.\n",
 			      file, linenum, args[0]);
 			goto out_err;
@@ -9219,9 +9444,34 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
 		LIST_INIT(&rule->arg.hdr_add.fmt);
 
 		proxy->conf.args.ctx = ARGC_HRS;
-		parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+		fmt_arg = (regfix_rule) ? args[cur_arg + 2] : args[cur_arg + 1];
+
+		if (regfix_rule && !*fmt_arg) {
+				Alert("parsing [%s:%d]: 'http-response %s' expects exactly 3 arguments.\n",
+			      file, linenum, args[0]);
+				goto out_err;
+		}
+		parse_logformat_string(fmt_arg, proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+					       (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
+					       file, linenum);
+
+		if (regfix_rule) {
+			if (!(rule->arg.hdr_add.re = (regex_t*)calloc(1, sizeof(regex_t)))) {
+				Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
+				goto out_err;
+			}
+
+			if (regcomp(rule->arg.hdr_add.re, args[cur_arg + 1], REG_EXTENDED)) {
+				Alert("parsing [%s:%d] : '%s' : bad regular expression.\n", file, linenum, 
+					args[cur_arg + 1]);
+				goto out_err;
+			}
+
+			parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
 				       (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
-				       file, linenum);
+				       file, linenum); 
+		}
+
 		free(proxy->conf.lfs_file);
 		proxy->conf.lfs_file = strdup(proxy->conf.args.file);
 		proxy->conf.lfs_line = proxy->conf.args.line;
@@ -9393,7 +9643,7 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
 		}
 		rule->cond = cond;
 	}
-	else if (*args[cur_arg]) {
+	else if (*args[cur_arg] && !regfix_rule) {
 		Alert("parsing [%s:%d]: 'http-response %s' expects"
 		      " either 'if' or 'unless' followed by a condition but found '%s'.\n",
 		      file, linenum, args[0], args[cur_arg]);

Reply via email to