MINOR: http_act: Add -m flag for del-header name matching method

This patch adds -m flag which allows to specify header name
matching method when deleting headers from http request/response.
Currently beg, end, sub, str and reg are supported.

This is related to GitHub issue #909

(cherry picked from commit ebdd4c55da4360bde7878604ea528c2031a26541)
Signed-off-by: William Lallemand <wlallemand@haproxy.org>
diff --git a/src/http_act.c b/src/http_act.c
index 27db478..13a5c37 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -1438,20 +1438,67 @@
 	return ACT_RET_PRS_OK;
 }
 
-/* Parse a "del-header" action. It takes an header name as argument. It returns
- * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
+/* This function executes a del-header action with selected matching mode for
+ * header name. It finds the matching method to be performed in <.action>, previously
+ * filled by function parse_http_del_header(). On success, it returns ACT_RET_CONT.
+ * Otherwise ACT_RET_ERR is returned.
+ */
+static enum act_return http_action_del_header(struct act_rule *rule, struct proxy *px,
+						  struct session *sess, struct stream *s, int flags)
+{
+	struct http_hdr_ctx ctx;
+	struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
+	struct htx *htx = htxbuf(&msg->chn->buf);
+	enum act_return ret = ACT_RET_CONT;
+
+	/* remove all occurrences of the header */
+	ctx.blk = NULL;
+	switch (rule->action) {
+	case PAT_MATCH_STR:
+		while (http_find_header(htx, rule->arg.http.str, &ctx, 1))
+			http_remove_header(htx, &ctx);
+		break;
+	case PAT_MATCH_BEG:
+		while (http_find_pfx_header(htx, rule->arg.http.str, &ctx, 1))
+			http_remove_header(htx, &ctx);
+		break;
+	case PAT_MATCH_END:
+		while (http_find_sfx_header(htx, rule->arg.http.str, &ctx, 1))
+			http_remove_header(htx, &ctx);
+		break;
+	case PAT_MATCH_SUB:
+		while (http_find_sub_header(htx, rule->arg.http.str, &ctx, 1))
+			http_remove_header(htx, &ctx);
+		break;
+	case PAT_MATCH_REG:
+		while (http_match_header(htx, rule->arg.http.re, &ctx, 1))
+			http_remove_header(htx, &ctx);
+		break;
+	default:
+		return ACT_RET_ERR;
+	}
+	return ret;
+}
+
+/* Parse a "del-header" action. It takes string as a required argument,
+ * optional flag (currently only -m) and optional matching method of input string
+ * with header name to be deleted. Default matching method is exact match (-m str).
+ * It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
  */
 static enum act_parse_ret parse_http_del_header(const char **args, int *orig_arg, struct proxy *px,
 						struct act_rule *rule, char **err)
 {
 	int cur_arg;
+	int pat_idx;
 
-	rule->action = ACT_HTTP_DEL_HDR;
+	/* set exact matching (-m str) as default */
+	rule->action = PAT_MATCH_STR;
+	rule->action_ptr = http_action_del_header;
 	rule->release_ptr = release_http_action;
 
 	cur_arg = *orig_arg;
 	if (!*args[cur_arg]) {
-		memprintf(err, "expects exactly 1 arguments");
+		memprintf(err, "expects at least 1 argument");
 		return ACT_RET_PRS_ERR;
 	}
 
@@ -1459,7 +1506,32 @@
 	rule->arg.http.str.len = strlen(rule->arg.http.str.ptr);
 	px->conf.args.ctx = (rule->from == ACT_F_HTTP_REQ ? ARGC_HRQ : ARGC_HRS);
 
+	if (strcmp(args[cur_arg+1], "-m") == 0) {
+		cur_arg++;
+		if (!*args[cur_arg+1]) {
+			memprintf(err, "-m flag expects exactly 1 argument");
+			return ACT_RET_PRS_ERR;
+		}
+
+		cur_arg++;
+		pat_idx = pat_find_match_name(args[cur_arg]);
+		switch (pat_idx) {
+		case PAT_MATCH_REG:
+			if (!(rule->arg.http.re = regex_comp(rule->arg.http.str.ptr, 1, 1, err)))
+				return ACT_RET_PRS_ERR;
+			/* fall through */
+		case PAT_MATCH_STR:
+		case PAT_MATCH_BEG:
+		case PAT_MATCH_END:
+		case PAT_MATCH_SUB:
+			rule->action = pat_idx;
+			break;
+		default:
+			memprintf(err, "-m with unsupported matching method '%s'", args[cur_arg]);
+			return ACT_RET_PRS_ERR;
+		}
+	}
+
-	LIST_INIT(&rule->arg.http.fmt);
 	*orig_arg = cur_arg + 1;
 	return ACT_RET_PRS_OK;
 }