From 46f95543c53b6ef74bdd5ba561e99e7452df1d5f Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Fri, 20 Dec 2019 10:07:22 +0100 Subject: [PATCH] MINOR: http-rules: Add a rule to enable or disable the strict rewriting mode 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 | 30 ++++++++++++++++++++++++++++ src/http_act.c | 46 +++++++++++++++++++++++++++++++++++++++++++ src/http_ana.c | 14 +++++++++++++ 3 files changed, 90 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index 24ba9bd12..6c0faac05 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4828,6 +4828,21 @@ http-request silent-drop [ { if | unless } ] 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 ] [ { if | unless } ] This stops the evaluation of the rules and immediately blocks the request @@ -5216,6 +5231,21 @@ http-response silent-drop [ { if | unless } ] 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 [table ] [ { if | unless } ] http-response track-sc1 [table
] [ { if | unless } ] http-response track-sc2 [table
] [ { if | unless } ] diff --git a/src/http_act.c b/src/http_act.c index f199e3b6b..cf0d8bf84 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -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 } } diff --git a/src/http_ana.c b/src/http_ana.c index f80da9a98..fa418bb5d 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -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; }