MINOR: http-rules: Make replace-header and replace-value custom actions

Now, these actions use their own dedicated function and are no longer handled
"in place" during the HTTP rules evaluation. Thus the action names
ACT_HTTP_REPLACE_HDR and ACT_HTTP_REPLACE_VAL are removed. The action type is
now set to 0 to evaluate the whole header or to 1 to evaluate every
comma-delimited values.

The function http_transform_header_str() is renamed to http_replace_hdrs() to be
more explicit and the function http_transform_header() is removed. In fact, this
last one is now more or less the new action function.

The lua code has been updated accordingly to use http_replace_hdrs().
diff --git a/src/hlua.c b/src/hlua.c
index 694b3ff..900bad7 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -4795,7 +4795,7 @@
  * 4 following functions.
  */
 __LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct hlua_txn *htxn,
-                                           struct http_msg *msg, int action)
+                                           struct http_msg *msg, int full)
 {
 	size_t name_len;
 	const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
@@ -4808,7 +4808,7 @@
 		WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
 
 	htx = htxbuf(&msg->chn->buf);
-	http_transform_header_str(htxn->s, msg->chn, htx, ist2(name, name_len), value, re, action);
+	http_replace_hdrs(htxn->s, htx, ist2(name, name_len), value, re, full);
 	regex_free(re);
 	return 0;
 }
@@ -4823,7 +4823,7 @@
 	if (htxn->dir != SMP_OPT_DIR_REQ || !(htxn->flags & HLUA_TXN_HTTP_RDY))
 		WILL_LJMP(lua_error(L));
 
-	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, ACT_HTTP_REPLACE_HDR));
+	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, 1));
 }
 
 __LJMP static int hlua_http_res_rep_hdr(lua_State *L)
@@ -4836,7 +4836,7 @@
 	if (htxn->dir != SMP_OPT_DIR_RES || !(htxn->flags & HLUA_TXN_HTTP_RDY))
 		WILL_LJMP(lua_error(L));
 
-	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, ACT_HTTP_REPLACE_HDR));
+	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, 1));
 }
 
 __LJMP static int hlua_http_req_rep_val(lua_State *L)
@@ -4849,7 +4849,7 @@
 	if (htxn->dir != SMP_OPT_DIR_REQ || !(htxn->flags & HLUA_TXN_HTTP_RDY))
 		WILL_LJMP(lua_error(L));
 
-	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, ACT_HTTP_REPLACE_VAL));
+	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, 0));
 }
 
 __LJMP static int hlua_http_res_rep_val(lua_State *L)
@@ -4862,7 +4862,7 @@
 	if (htxn->dir != SMP_OPT_DIR_RES || !(htxn->flags & HLUA_TXN_HTTP_RDY))
 		WILL_LJMP(lua_error(L));
 
-	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, ACT_HTTP_REPLACE_VAL));
+	return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, 0));
 }
 
 /* This function deletes all the occurrences of an header.
diff --git a/src/http_act.c b/src/http_act.c
index 9fe6a68..33e3ff4 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -990,6 +990,56 @@
 	return ACT_RET_PRS_OK;
 }
 
+/* This function executes a replace-header or replace-value actions. It
+ * builds a string in the trash from the specified format string. It finds
+ * the action to be performed in <.action>, previously filled by function
+ * parse_replace_header(). The replacement action is excuted by the function
+ * http_action_replace_header(). On success, it returns ACT_RET_CONT. If an error
+ * occurs while soft rewrites are enabled, the action is canceled, but the rule
+ * processing continue. Otherwsize ACT_RET_ERR is returned.
+ */
+static enum act_return http_action_replace_header(struct act_rule *rule, struct proxy *px,
+						  struct session *sess, struct stream *s, int flags)
+{
+	struct htx *htx = htxbuf((rule->from == ACT_F_HTTP_REQ) ? &s->req.buf : &s->res.buf);
+	enum act_return ret = ACT_RET_CONT;
+	struct buffer *replace;
+	int r;
+
+	replace = alloc_trash_chunk();
+	if (!replace)
+		goto fail_alloc;
+
+	replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
+
+	r = http_replace_hdrs(s, htx, rule->arg.http.str, replace->area, rule->arg.http.re, (rule->action == 0));
+	if (r == -1)
+		goto fail_rewrite;
+
+  leave:
+	free_trash_chunk(replace);
+	return ret;
+
+  fail_alloc:
+	if (!(s->flags & SF_ERR_MASK))
+		s->flags |= SF_ERR_RESOURCE;
+	ret = ACT_RET_ERR;
+	goto leave;
+
+  fail_rewrite:
+	_HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_rewrites, 1);
+	if (s->flags & SF_BE_ASSIGNED)
+		_HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
+	if (sess->listener->counters)
+		_HA_ATOMIC_ADD(&sess->listener->counters->failed_rewrites, 1);
+	if (objt_server(s->target))
+		_HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
+
+	if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW))
+		ret = ACT_RET_ERR;
+	goto leave;
+}
+
 /* Parse a "replace-header" or "replace-value" actions. It takes an header name,
  * a regex and replacement string as arguments. It returns ACT_RET_PRS_OK on
  * success, ACT_RET_PRS_ERR on error.
@@ -999,7 +1049,11 @@
 {
 	int cap, cur_arg;
 
-	rule->action = args[*orig_arg-1][8] == 'h' ? ACT_HTTP_REPLACE_HDR : ACT_HTTP_REPLACE_VAL;
+	if (args[*orig_arg-1][8] == 'h')
+		rule->action = 0; // replace-header
+	else
+		rule->action = 1; // replace-value
+	rule->action_ptr = http_action_replace_header;
 
 	cur_arg = *orig_arg;
 	if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2]) {
diff --git a/src/http_ana.c b/src/http_ana.c
index 171ddfd..a9961fe 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -2704,15 +2704,19 @@
 	return 0;
 }
 
-int http_transform_header_str(struct stream* s, struct channel *chn, struct htx *htx,
-			      struct ist name, const char *str, struct my_regex *re, int action)
+/* Replace all headers matching the name <name>. The header value is replaced if
+ * it matches the regex <re>. <str> is used for the replacement. If <full> is
+ * set to 1, the full-line is matched and replaced. Otherwise, comma-separated
+ * values are evaluated one by one. It returns 0 on success and -1 on error.
+ */
+int http_replace_hdrs(struct stream* s, struct htx *htx, struct ist name,
+		     const char *str, struct my_regex *re, int full)
 {
 	struct http_hdr_ctx ctx;
 	struct buffer *output = get_trash_chunk();
 
-	/* find full header is action is ACT_HTTP_REPLACE_HDR */
 	ctx.blk = NULL;
-	while (http_find_header(htx, name, &ctx, (action == ACT_HTTP_REPLACE_HDR))) {
+	while (http_find_header(htx, name, &ctx, full)) {
 		if (!regex_exec_match2(re, ctx.value.ptr, ctx.value.len, MAX_MATCH, pmatch, 0))
 			continue;
 
@@ -2725,48 +2729,6 @@
 	return 0;
 }
 
-static int http_transform_header(struct stream* s, struct channel *chn, struct htx *htx,
-				 const struct ist name, struct list *fmt, struct my_regex *re, int action)
-{
-	struct buffer *replace;
-	int ret = 0;
-
-	replace = alloc_trash_chunk();
-	if (!replace)
-		goto fail_alloc;
-
-	replace->data = build_logline(s, replace->area, replace->size, fmt);
-	if (replace->data >= replace->size - 1)
-		goto fail_rewrite;
-
-	if (http_transform_header_str(s, chn, htx, name, replace->area, re, action) == -1)
-		goto fail_rewrite;
-
-  leave:
-	free_trash_chunk(replace);
-	return ret;
-
-  fail_alloc:
-	if (!(s->flags & SF_ERR_MASK))
-		s->flags |= SF_ERR_RESOURCE;
-	ret = -1;
-	goto leave;
-
-  fail_rewrite:
-	_HA_ATOMIC_ADD(&s->sess->fe->fe_counters.failed_rewrites, 1);
-	if (s->flags & SF_BE_ASSIGNED)
-		_HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
-	if (s->sess->listener->counters)
-		_HA_ATOMIC_ADD(&s->sess->listener->counters->failed_rewrites, 1);
-	if (objt_server(s->target))
-		_HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
-
-	if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW))
-		ret = -1;
-	goto leave;
-}
-
-
 /* Terminate a 103-Erly-hints response and send it to the client. It returns 0
  * on success and -1 on error. The response channel is updated accordingly.
  */
@@ -3069,16 +3031,6 @@
 				s->logs.level = rule->arg.http.i;
 				break;
 
-			case ACT_HTTP_REPLACE_HDR:
-			case ACT_HTTP_REPLACE_VAL:
-				if (http_transform_header(s, &s->req, htx, rule->arg.http.str,
-							  &rule->arg.http.fmt,
-							  rule->arg.http.re, rule->action)) {
-					rule_ret = HTTP_RULE_RES_ERROR;
-					goto end;
-				}
-				break;
-
 			case ACT_HTTP_DEL_HDR:
 				/* remove all occurrences of the header */
 				ctx.blk = NULL;
@@ -3441,16 +3393,6 @@
 				s->logs.level = rule->arg.http.i;
 				break;
 
-			case ACT_HTTP_REPLACE_HDR:
-			case ACT_HTTP_REPLACE_VAL:
-				if (http_transform_header(s, &s->res, htx, rule->arg.http.str,
-							  &rule->arg.http.fmt,
-							  rule->arg.http.re, rule->action)) {
-					rule_ret = HTTP_RULE_RES_ERROR;
-					goto end;
-				}
-				break;
-
 			case ACT_HTTP_DEL_HDR:
 				/* remove all occurrences of the header */
 				ctx.blk = NULL;