]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-rules: Add a rule to enable or disable the strict rewriting mode
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 20 Dec 2019 09:07:22 +0000 (10:07 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 20 Jan 2020 14:18:45 +0000 (15:18 +0100)
It is now possible to explicitly instruct rewriting rules to be strict or not
towards errors. It means that in this mode, an internal error is trigger if a
rewrite rule fails. The HTTP action "strict-mode" can be used to enable or
disable the strict rewriting mode. It can be used in an http-request and an
http-response ruleset.

For now, by default the strict rewriting mode is disabled. Because it is the
current behavior. But it will be changed in another patch.

doc/configuration.txt
src/http_act.c
src/http_ana.c

index 24ba9bd125a2e3a40610fd693d3d57f5d60c2cff..6c0faac05b83875b352827429731905d4ae34e86 100644 (file)
@@ -4828,6 +4828,21 @@ http-request silent-drop [ { if | unless } <condition> ]
   router, though it's still delivered to local networks. Do not use it unless
   you fully understand how it works.
 
+http-request strict-mode { on | off }
+
+  This enables or disables the strict rewriting mode for following rules. It
+  does not affect rules declared before it and it is only applicable on rules
+  performing a rewrite on the requests. When the strict mode is enabled, any
+  rewrite failure triggers an internal error. Otherwise, such errors are
+  silently ignored. The purpose of the strict rewriting mode is to make some
+  rewrites optionnal while others must be performed to continue the request
+  processing.
+
+  By default, the strict rewriting mode is disabled. Its value is also reset
+  when a ruleset evaluation ends. So, for instance, if you change the mode on
+  the frontend, the default mode is restored when HAProxy starts the backend
+  rules evaluation.
+
 http-request tarpit [deny_status <status>] [ { if | unless } <condition> ]
 
   This stops the evaluation of the rules and immediately blocks the request
@@ -5216,6 +5231,21 @@ http-response silent-drop [ { if | unless } <condition> ]
   router, though it's still delivered to local networks. Do not use it unless
   you fully understand how it works.
 
+http-response strict-mode { on | off }
+
+  This enables or disables the strict rewriting mode for following rules. It
+  does not affect rules declared before it and it is only applicable on rules
+  performing a rewrite on the responses. When the strict mode is enabled, any
+  rewrite failure triggers an internal error. Otherwise, such errors are
+  silently ignored. The purpose of the strict rewriting mode is to make some
+  rewrites optionnal while others must be performed to continue the response
+  processing.
+
+  By default, the strict rewriting mode is disabled. Its value is also reset
+  when a ruleset evaluation ends. So, for instance, if you change the mode on
+  the bacnkend, the default mode is restored when HAProxy starts the frontend
+  rules evaluation.
+
 http-response track-sc0 <key> [table <table>] [ { if | unless } <condition> ]
 http-response track-sc1 <key> [table <table>] [ { if | unless } <condition> ]
 http-response track-sc2 <key> [table <table>] [ { if | unless } <condition> ]
index f199e3b6b36d7f3c76270a5aa2c73210887b69b2..cf0d8bf84efec4bff53ded95705437004a6bc41d 100644 (file)
@@ -1211,6 +1211,50 @@ static enum act_parse_ret parse_http_track_sc(const char **args, int *orig_arg,
        return ACT_RET_PRS_OK;
 }
 
+/* This function executes a strict-mode actions. On success, it always returns
+ * ACT_RET_CONT
+ */
+static enum act_return http_action_strict_mode(struct act_rule *rule, struct proxy *px,
+                                              struct session *sess, struct stream *s, int flags)
+{
+       struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
+
+       if (rule->action == 0) // strict-mode on
+               msg->flags &= ~HTTP_MSGF_SOFT_RW;
+       else // strict-mode off
+               msg->flags |= HTTP_MSGF_SOFT_RW;
+       return ACT_RET_CONT;
+}
+
+/* Parse a "strict-mode" action. It returns ACT_RET_PRS_OK on success,
+ * ACT_RET_PRS_ERR on error.
+ */
+static enum act_parse_ret parse_http_strict_mode(const char **args, int *orig_arg, struct proxy *px,
+                                                struct act_rule *rule, char **err)
+{
+       int cur_arg;
+
+
+       cur_arg = *orig_arg;
+       if (!*args[cur_arg]) {
+               memprintf(err, "expects exactly 1 arguments");
+               return ACT_RET_PRS_ERR;
+       }
+
+       if (strcasecmp(args[cur_arg], "on") == 0)
+               rule->action = 0; // strict-mode on
+       else if (strcasecmp(args[cur_arg], "off") == 0)
+               rule->action = 1; // strict-mode off
+       else {
+               memprintf(err, "Unexpected value '%s'. Only 'on' and 'off' are supported", args[cur_arg]);
+               return ACT_RET_PRS_ERR;
+       }
+       rule->action_ptr = http_action_strict_mode;
+
+       *orig_arg = cur_arg + 1;
+       return ACT_RET_PRS_OK;
+}
+
 /************************************************************************/
 /*   All supported http-request action keywords must be declared here.  */
 /************************************************************************/
@@ -1244,6 +1288,7 @@ static struct action_kw_list http_req_actions = {
                { "set-query",        parse_set_req_line,              0 },
                { "set-tos",          parse_http_set_tos,              0 },
                { "set-uri",          parse_set_req_line,              0 },
+               { "strict-mode",      parse_http_strict_mode,          0 },
                { "tarpit",           parse_http_req_deny,             0 },
                { "track-sc",         parse_http_track_sc,             1 },
                { NULL, NULL }
@@ -1272,6 +1317,7 @@ static struct action_kw_list http_res_actions = {
                { "set-nice",        parse_http_set_nice,       0 },
                { "set-status",      parse_http_set_status,     0 },
                { "set-tos",         parse_http_set_tos,        0 },
+               { "strict-mode",     parse_http_strict_mode,    0 },
                { "track-sc",        parse_http_track_sc,       1 },
                { NULL, NULL }
        }
index f80da9a98353fd8a6ec8a23211321f9af2aaac04..fa418bb5d0cea2f1390a6d6a2a342b8d989fddc3 100644 (file)
@@ -2943,6 +2943,9 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
        }
        s->current_rule_list = rules;
 
+       /* start the ruleset evaluation in soft mode */
+       txn->req.flags |= HTTP_MSGF_SOFT_RW;
+
        list_for_each_entry(rule, rules, list) {
                /* check optional condition */
                if (rule->cond) {
@@ -3309,6 +3312,10 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
                        rule_ret = HTTP_RULE_RES_ERROR;
        }
 
+       /* if the ruleset evaluation is finished reset the soft mode */
+       if (rule_ret != HTTP_RULE_RES_YIELD)
+               txn->req.flags |= HTTP_MSGF_SOFT_RW;
+
        /* we reached the end of the rules, nothing to report */
        return rule_ret;
 }
@@ -3349,6 +3356,9 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis
        }
        s->current_rule_list = rules;
 
+       /* start the ruleset evaluation in soft mode */
+       txn->rsp.flags |= HTTP_MSGF_SOFT_RW;
+
        list_for_each_entry(rule, rules, list) {
                /* check optional condition */
                if (rule->cond) {
@@ -3671,6 +3681,10 @@ resume_execution:
        }
 
   end:
+       /* if the ruleset evaluation is finished reset the soft mode */
+       if (rule_ret != HTTP_RULE_RES_YIELD)
+               txn->rsp.flags |= HTTP_MSGF_SOFT_RW;
+
        /* we reached the end of the rules, nothing to report */
        return rule_ret;
 }