MINOR: action: implement experimental actions

Support experimental actions. It is mandatory to use
'expose-experimental-directives' before to be able to use them.

If such action is present in the config file, the tainted status of the
process is updated. Another tainted status is set when an experimental
action is executed.
diff --git a/include/haproxy/global.h b/include/haproxy/global.h
index fb7b62b..c69955c 100644
--- a/include/haproxy/global.h
+++ b/include/haproxy/global.h
@@ -99,6 +99,7 @@
 /* handle 'tainted' status */
 enum tainted_flags {
 	TAINTED_CONFIG_EXP_KW_DECLARED = 0x1,
+	TAINTED_ACTION_EXP_EXECUTED    = 0x2,
 };
 void mark_tainted(const enum tainted_flags flag);
 unsigned int get_tainted();
diff --git a/src/http_ana.c b/src/http_ana.c
index b356646..a3618b9 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -16,6 +16,7 @@
 #include <haproxy/backend.h>
 #include <haproxy/base64.h>
 #include <haproxy/capture-t.h>
+#include <haproxy/cfgparse.h>
 #include <haproxy/channel.h>
 #include <haproxy/check.h>
 #include <haproxy/connection.h>
@@ -2798,6 +2799,9 @@
 
 		act_opts |= ACT_OPT_FIRST;
   resume_execution:
+		if (rule->kw->flags & KWF_EXPERIMENTAL)
+			mark_tainted(TAINTED_ACTION_EXP_EXECUTED);
+
 		/* Always call the action function if defined */
 		if (rule->action_ptr) {
 			if ((s->req.flags & CF_READ_ERROR) ||
@@ -2943,6 +2947,8 @@
 
 		act_opts |= ACT_OPT_FIRST;
 resume_execution:
+		if (rule->kw->flags & KWF_EXPERIMENTAL)
+			mark_tainted(TAINTED_ACTION_EXP_EXECUTED);
 
 		/* Always call the action function if defined */
 		if (rule->action_ptr) {
diff --git a/src/http_rules.c b/src/http_rules.c
index a34c560..54fa0e9 100644
--- a/src/http_rules.c
+++ b/src/http_rules.c
@@ -92,6 +92,16 @@
 		cur_arg = 1;
 		/* try in the module list */
 		rule->kw = custom;
+
+		if (custom->flags & KWF_EXPERIMENTAL) {
+			if (!experimental_directives_allowed) {
+				ha_alert("parsing [%s:%d] : '%s' action is experimental, must be allowed via a global 'expose-experimental-directives'\n",
+				         file, linenum, custom->kw);
+				goto out_err;
+			}
+			mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
+		}
+
 		if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
 			ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
 				 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
@@ -161,6 +171,16 @@
 		cur_arg = 1;
 		/* try in the module list */
 		rule->kw = custom;
+
+		if (custom->flags & KWF_EXPERIMENTAL) {
+			if (!experimental_directives_allowed) {
+				ha_alert("parsing [%s:%d] : '%s' action is experimental, must be allowed via a global 'expose-experimental-directives'\n",
+				         file, linenum, custom->kw);
+				goto out_err;
+			}
+			mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
+		}
+
 		if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) == ACT_RET_PRS_ERR) {
 			ha_alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
 				 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);